From e5f18b22e0b9aa4e0430f1a90d26f53dff9d44b3 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Thu, 16 Dec 2021 20:27:58 +0900 Subject: [PATCH 01/24] feat(iotevents): add DetectorModel L2 Construct --- packages/@aws-cdk/aws-iotevents/README.md | 23 ++++- .../aws-iotevents/lib/detector-model.ts | 46 ++++++++++ packages/@aws-cdk/aws-iotevents/lib/index.ts | 2 + packages/@aws-cdk/aws-iotevents/lib/state.ts | 60 ++++++++++++++ packages/@aws-cdk/aws-iotevents/package.json | 2 + .../aws-iotevents/test/detector-model.test.ts | 83 +++++++++++++++++++ .../test/integ.detector-model.expected.json | 57 ++++++++++++- .../test/integ.detector-model.ts | 16 +++- 8 files changed, 282 insertions(+), 7 deletions(-) create mode 100644 packages/@aws-cdk/aws-iotevents/lib/detector-model.ts create mode 100644 packages/@aws-cdk/aws-iotevents/lib/state.ts create mode 100644 packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 6dc6a681636cc..eeb7a7ad5e545 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -40,15 +40,30 @@ Import it into your code: import * as iotevents from '@aws-cdk/aws-iotevents'; ``` -## `Input` +## `DetectorModel` -Add an AWS IoT Events input to your stack: +The following example creates an AWS IoT Events detector dodel to your stack. +The detector must have at least one reference to an AWS IoT Events input. +AWS IoT Events input enable that the detector can get MQTT payload values from IoT Core rules. ```ts import * as iotevents from '@aws-cdk/aws-iotevents'; -new iotevents.Input(this, 'MyInput', { - inputName: 'my_input', +const input = new iotevents.Input(this, 'MyInput', { + inputName: 'my_input', // optional attributeJsonPaths: ['payload.temperature'], }); + +const onlineState = new iotevents.State({ + stateName: 'online', + onEnterEvents: [{ + eventName: 'test-event', + condition: `currentInput("${input.inputName}")`, + }], +}); + +new iotevents.DetectorModel(this, 'MyDetectorModel', { + detectorModelName: 'test-detector-model', // optional + initialState: onlineState, +}); ``` diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts new file mode 100644 index 0000000000000..935d2a8c030cc --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -0,0 +1,46 @@ +import * as iam from '@aws-cdk/aws-iam'; +import { Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnDetectorModel } from './iotevents.generated'; +import { State } from './state'; + +/** + * Properties for defining an AWS IoT Events detector model + */ +export interface DetectorModelProps { + /** + * The name of the detector model + * + * @default - CloudFormation will generate a unique name of the detector model + */ + readonly detectorModelName?: string, + + /** + * The state that is entered at the creation of each detector. + */ + readonly initialState: State; +} + +/** + * Defines an AWS IoT Events detector model in this stack. + */ +export class DetectorModel extends Resource { + constructor(scope: Construct, id: string, props: DetectorModelProps) { + super(scope, id, { + physicalName: props.detectorModelName, + }); + + const role = new iam.Role(this, 'DetectorModelRole', { + assumedBy: new iam.ServicePrincipal('iotevents.amazonaws.com'), + }); + + new CfnDetectorModel(this, 'Resource', { + detectorModelName: this.physicalName, + detectorModelDefinition: { + initialStateName: props.initialState.stateName, + states: [props.initialState.toStateJson()], + }, + roleArn: role.roleArn, + }); + } +} diff --git a/packages/@aws-cdk/aws-iotevents/lib/index.ts b/packages/@aws-cdk/aws-iotevents/lib/index.ts index 3851e30984391..77d2d2d34cdc8 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/index.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/index.ts @@ -1,4 +1,6 @@ export * from './input'; +export * from './detector-model'; +export * from './state'; // AWS::IoTEvents CloudFormation Resources: export * from './iotevents.generated'; diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts new file mode 100644 index 0000000000000..77754ea1b38f5 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -0,0 +1,60 @@ +import { CfnDetectorModel } from './iotevents.generated'; + +/** + * Specifies the actions to be performed when the condition evaluates to TRUE. + */ +export interface Event { + /** + * The name of the event + */ + readonly eventName: string; + + /** + * The Boolean expression that, when TRUE, causes the actions to be performed. + * + * @default None - Defaults to perform the actions always. + */ + readonly condition?: string; +} + +/** + * Properties for defining a state of a detector + */ +export interface StateProps { + /** + * The name of the state + */ + readonly stateName: string + + /** + * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE` + * + * @default None + */ + readonly onEnterEvents?: Event[] +} + +/** + * Defines a state of a detector + */ +export class State { + /** + * The name of the state + */ + public readonly stateName: string; + + constructor(private readonly props: StateProps) { + this.stateName = props.stateName; + } + + /** + * Return the state property JSON + */ + public toStateJson(): CfnDetectorModel.StateProperty { + const { stateName, onEnterEvents } = this.props; + return { + stateName, + onEnter: onEnterEvents && { events: onEnterEvents }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 50ed464cf76d7..5612efe13f8da 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -84,10 +84,12 @@ }, "dependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts new file mode 100644 index 0000000000000..63f4ef29edaa2 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -0,0 +1,83 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as cdk from '@aws-cdk/core'; +import * as iotevents from '../lib'; + +test('Default property', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + InitialStateName: 'test-state', + States: [{ + StateName: 'test-state', + }], + }, + RoleArn: { + 'Fn::GetAtt': ['MyDetectorModelDetectorModelRoleF2FB4D88', 'Arn'], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [{ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'iotevents.amazonaws.com' }, + }], + }, + }); +}); + +test('can set physical name', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + detectorModelName: 'test-detector-model', + initialState: new iotevents.State({ stateName: 'test-state' }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelName: 'test-detector-model', + }); +}); + +test('can set onEnterEvents', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: 'test-eventCondition', + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [{ + EventName: 'test-eventName', + Condition: 'test-eventCondition', + }], + }, + }), + ], + }, + }); +}); 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 1f5d452b5475d..7f241a6cc847a 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 @@ -9,8 +9,63 @@ "JsonPath": "payload.temperature" } ] + } + } + }, + "MyDetectorModelDetectorModelRoleF2FB4D88": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iotevents.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyDetectorModel559C0B0E": { + "Type": "AWS::IoTEvents::DetectorModel", + "Properties": { + "DetectorModelDefinition": { + "InitialStateName": "online", + "States": [ + { + "OnEnter": { + "Events": [ + { + "Condition": { + "Fn::Join": [ + "", + [ + "currentInput(\"", + { + "Ref": "MyInput08947B23" + }, + "\")" + ] + ] + }, + "EventName": "test-event" + } + ] + }, + "StateName": "online" + } + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "MyDetectorModelDetectorModelRoleF2FB4D88", + "Arn" + ] }, - "InputName": "test_input" + "DetectorModelName": "test-detector-model" } } } 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 cb900c83a3f44..316b29516e6f1 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -7,10 +7,22 @@ class TestStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); - new iotevents.Input(this, 'MyInput', { - inputName: 'test_input', + const input = new iotevents.Input(this, 'MyInput', { attributeJsonPaths: ['payload.temperature'], }); + + const onlineState = new iotevents.State({ + stateName: 'online', + onEnterEvents: [{ + eventName: 'test-event', + condition: `currentInput("${input.inputName}")`, + }], + }); + + new iotevents.DetectorModel(this, 'MyDetectorModel', { + detectorModelName: 'test-detector-model', + initialState: onlineState, + }); } } From 7873d17e146ec8f07fd56f00e13b58694a4f29e4 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Thu, 16 Dec 2021 20:53:52 +0900 Subject: [PATCH 02/24] cut out the event. --- packages/@aws-cdk/aws-iotevents/lib/event.ts | 16 ++++++++++++++++ packages/@aws-cdk/aws-iotevents/lib/index.ts | 3 ++- packages/@aws-cdk/aws-iotevents/lib/state.ts | 18 +----------------- 3 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 packages/@aws-cdk/aws-iotevents/lib/event.ts diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts new file mode 100644 index 0000000000000..2418b4513676e --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -0,0 +1,16 @@ +/** + * Specifies the actions to be performed when the condition evaluates to TRUE. + */ +export interface Event { + /** + * The name of the event + */ + readonly eventName: string; + + /** + * The Boolean expression that, when TRUE, causes the actions to be performed. + * + * @default None - Defaults to perform the actions always. + */ + readonly condition?: string; +} diff --git a/packages/@aws-cdk/aws-iotevents/lib/index.ts b/packages/@aws-cdk/aws-iotevents/lib/index.ts index 77d2d2d34cdc8..7433e256c58c1 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/index.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/index.ts @@ -1,5 +1,6 @@ -export * from './input'; export * from './detector-model'; +export * from './event'; +export * from './input'; export * from './state'; // AWS::IoTEvents CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 77754ea1b38f5..8f03721637c0c 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -1,22 +1,6 @@ +import { Event } from './event'; import { CfnDetectorModel } from './iotevents.generated'; -/** - * Specifies the actions to be performed when the condition evaluates to TRUE. - */ -export interface Event { - /** - * The name of the event - */ - readonly eventName: string; - - /** - * The Boolean expression that, when TRUE, causes the actions to be performed. - * - * @default None - Defaults to perform the actions always. - */ - readonly condition?: string; -} - /** * Properties for defining a state of a detector */ From 07081ed0b918ecd372b4437ff52a0b0b1ecd021d Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Thu, 16 Dec 2021 21:06:08 +0900 Subject: [PATCH 03/24] fix readme --- packages/@aws-cdk/aws-iotevents/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index eeb7a7ad5e545..7462de0b4ab83 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -43,7 +43,7 @@ import * as iotevents from '@aws-cdk/aws-iotevents'; ## `DetectorModel` The following example creates an AWS IoT Events detector dodel to your stack. -The detector must have at least one reference to an AWS IoT Events input. +The detector model need a reference to at least one AWS IoT Events input. AWS IoT Events input enable that the detector can get MQTT payload values from IoT Core rules. ```ts From 3d2db0763e69eb3233e957a5d7a0cdadd5687b13 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Fri, 17 Dec 2021 22:00:44 +0900 Subject: [PATCH 04/24] address comments --- .../aws-iotevents/lib/detector-model.ts | 42 +++++++++++++-- packages/@aws-cdk/aws-iotevents/lib/state.ts | 4 +- packages/@aws-cdk/aws-iotevents/package.json | 4 +- .../aws-iotevents/test/detector-model.test.ts | 53 +++++++++++++++++++ .../test/integ.detector-model.expected.json | 3 +- .../test/integ.detector-model.ts | 1 + 6 files changed, 97 insertions(+), 10 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 935d2a8c030cc..d7e528fa1d9bc 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -1,9 +1,20 @@ import * as iam from '@aws-cdk/aws-iam'; -import { Resource } from '@aws-cdk/core'; +import { Resource, IResource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnDetectorModel } from './iotevents.generated'; import { State } from './state'; +/** + * Represents an AWS IoT Events detector model + */ +export interface IDetectorModel extends IResource { + /** + * The name of the detector model + * @attribute + */ + readonly detectorModelName: string; +} + /** * Properties for defining an AWS IoT Events detector model */ @@ -13,28 +24,47 @@ export interface DetectorModelProps { * * @default - CloudFormation will generate a unique name of the detector model */ - readonly detectorModelName?: string, + readonly detectorModelName?: string; /** * The state that is entered at the creation of each detector. */ readonly initialState: State; + + /** + * The role that grants permission to AWS IoT Events to perform its operations. + * + * @default - a role will be created with default permissions. + */ + readonly role?: iam.IRole; } /** * Defines an AWS IoT Events detector model in this stack. */ -export class DetectorModel extends Resource { +export class DetectorModel extends Resource implements IDetectorModel { + /** + * Import an existing detector model + */ + public static fromDetectorModelName(scope: Construct, id: string, detectorModelName: string): IDetectorModel { + class Import extends Resource implements IDetectorModel { + public readonly detectorModelName = detectorModelName; + } + return new Import(scope, id); + } + + public readonly detectorModelName: string; + constructor(scope: Construct, id: string, props: DetectorModelProps) { super(scope, id, { physicalName: props.detectorModelName, }); - const role = new iam.Role(this, 'DetectorModelRole', { + const role = props.role ?? new iam.Role(this, 'DetectorModelRole', { assumedBy: new iam.ServicePrincipal('iotevents.amazonaws.com'), }); - new CfnDetectorModel(this, 'Resource', { + const resource = new CfnDetectorModel(this, 'Resource', { detectorModelName: this.physicalName, detectorModelDefinition: { initialStateName: props.initialState.stateName, @@ -42,5 +72,7 @@ export class DetectorModel extends Resource { }, roleArn: role.roleArn, }); + + this.detectorModelName = this.getResourceNameAttribute(resource.ref); } } diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 8f03721637c0c..d3f05a0d4a7f9 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -8,14 +8,14 @@ export interface StateProps { /** * The name of the state */ - readonly stateName: string + readonly stateName: string; /** * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE` * * @default None */ - readonly onEnterEvents?: Event[] + readonly onEnterEvents?: Event[]; } /** diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 5612efe13f8da..34e9f5b6c77f4 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -83,13 +83,13 @@ "jest": "^27.3.1" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { 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 63f4ef29edaa2..7077c47af326b 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -1,4 +1,5 @@ import { Match, Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as iotevents from '../lib'; @@ -36,6 +37,29 @@ test('Default property', () => { }); }); +test('can get detector model name', () => { + const stack = new cdk.Stack(); + // GIVEN + const detectorModel = new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + }), + }); + + // WHEN + new cdk.CfnResource(stack, 'Res', { + type: 'Test::Resource', + properties: { + DetectorModelName: detectorModel.detectorModelName, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('Test::Resource', { + DetectorModelName: { Ref: 'MyDetectorModel559C0B0E' }, + }); +}); + test('can set physical name', () => { const stack = new cdk.Stack(); @@ -81,3 +105,32 @@ test('can set onEnterEvents', () => { }, }); }); + +test('can set role', () => { + const stack = new cdk.Stack(); + + // WHEN + const role = iam.Role.fromRoleArn(stack, 'test-role', 'arn:aws:iam::123456789012:role/ForTest'); + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + role, + initialState: new iotevents.State({ stateName: 'test-state' }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + RoleArn: 'arn:aws:iam::123456789012:role/ForTest', + }); +}); + +test('can import a DetectorModel by detectorModelName', () => { + const stack = new cdk.Stack(); + + // WHEN + const detectorModelName = 'detector-model-name'; + const detectorModel = iotevents.DetectorModel.fromDetectorModelName(stack, 'ExistingDetectorModel', detectorModelName); + + // THEN + expect(detectorModel).toMatchObject({ + detectorModelName: detectorModelName, + }); +}); 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 7f241a6cc847a..517abb207d2f8 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 @@ -9,7 +9,8 @@ "JsonPath": "payload.temperature" } ] - } + }, + "InputName": "test_input" } }, "MyDetectorModelDetectorModelRoleF2FB4D88": { 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 316b29516e6f1..2a65816640bee 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -8,6 +8,7 @@ class TestStack extends cdk.Stack { super(scope, id, props); const input = new iotevents.Input(this, 'MyInput', { + inputName: 'test_input', attributeJsonPaths: ['payload.temperature'], }); From 0723a1c6b027d4a8f299304e30dc75ed2c1e8111 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Wed, 19 Jan 2022 23:44:14 +0900 Subject: [PATCH 05/24] implement Expressions --- packages/@aws-cdk/aws-iotevents/README.md | 2 +- .../aws-iotevents/lib/detector-model.ts | 4 + packages/@aws-cdk/aws-iotevents/lib/event.ts | 14 +- .../@aws-cdk/aws-iotevents/lib/expression.ts | 75 ++++++ packages/@aws-cdk/aws-iotevents/lib/index.ts | 1 + packages/@aws-cdk/aws-iotevents/lib/state.ts | 11 +- .../aws-iotevents/test/detector-model.test.ts | 213 +++++++++++++++++- .../test/integ.detector-model.expected.json | 6 +- .../test/integ.detector-model.ts | 9 +- 9 files changed, 318 insertions(+), 17 deletions(-) create mode 100644 packages/@aws-cdk/aws-iotevents/lib/expression.ts diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 7462de0b4ab83..0270792af3be9 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -58,7 +58,7 @@ const onlineState = new iotevents.State({ stateName: 'online', onEnterEvents: [{ eventName: 'test-event', - condition: `currentInput("${input.inputName}")`, + condition: iotevents.Expression.currentInput(input), }], }); diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index d7e528fa1d9bc..cbc33b09a2896 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -60,6 +60,10 @@ export class DetectorModel extends Resource implements IDetectorModel { physicalName: props.detectorModelName, }); + if (!props.initialState.hasCondition()) { + throw new Error('Detector Model must use at least one Input in a condition.'); + } + const role = props.role ?? new iam.Role(this, 'DetectorModelRole', { assumedBy: new iam.ServicePrincipal('iotevents.amazonaws.com'), }); diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts index 2418b4513676e..c8a67b661120d 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/event.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -1,3 +1,6 @@ +import { Expression } from './expression'; +import { CfnDetectorModel } from './iotevents.generated'; + /** * Specifies the actions to be performed when the condition evaluates to TRUE. */ @@ -12,5 +15,14 @@ export interface Event { * * @default None - Defaults to perform the actions always. */ - readonly condition?: string; + readonly condition?: Expression; +} + +export function getEventJson(events: Event[]): CfnDetectorModel.EventProperty[] { + return events.map(e => { + return { + eventName: e.eventName, + condition: e.condition?.evaluate(), + }; + }); } diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts new file mode 100644 index 0000000000000..8217bcf69062a --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -0,0 +1,75 @@ +import { IInput } from './input'; + +/** + * Expression for events in Detector Model state + * @see https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html + */ +export abstract class Expression { + /** + * Create a expression from the given string + */ + public static fromString(value: string): Expression { + return new StringExpression(value); + } + + /** + * Create a expression for function `currentInput()`. + * It is evaluated to true if the specified input message was received. + */ + public static currentInput(input: IInput): Expression { + return this.fromString(`currentInput("${input.inputName}")`); + } + + /** + * Create a expression for get an input attribute as `$input.TemperatureInput.temperatures[2]`. + */ + public static inputAttribute(input: IInput, path: string): Expression { + return this.fromString(`$input.${input.inputName}.${path}`); + } + + /** + * Create a expression for the Equal operator + */ + public static eq(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '==', right); + } + + /** + * Create a expression for the AND operator + */ + public static and(left: Expression, right: Expression): Expression { + return new BinaryOperationExpression(left, '&&', right); + } + + constructor() { + } + + /** + * this is called to evaluate the expression + */ + public abstract evaluate(): string; +} + +class StringExpression extends Expression { + constructor(private readonly value: string) { + super(); + } + + public evaluate() { + return this.value; + } +} + +class BinaryOperationExpression extends Expression { + constructor( + private readonly left: Expression, + private readonly operater: string, + private readonly right: Expression, + ) { + super(); + } + + public evaluate() { + return `${this.left.evaluate()} ${this.operater} ${this.right.evaluate()}`; + } +} diff --git a/packages/@aws-cdk/aws-iotevents/lib/index.ts b/packages/@aws-cdk/aws-iotevents/lib/index.ts index 7433e256c58c1..24913635ebe50 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/index.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/index.ts @@ -1,5 +1,6 @@ export * from './detector-model'; export * from './event'; +export * from './expression'; export * from './input'; export * from './state'; diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index d3f05a0d4a7f9..ac6fec5262e0c 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -1,4 +1,4 @@ -import { Event } from './event'; +import { Event, getEventJson } from './event'; import { CfnDetectorModel } from './iotevents.generated'; /** @@ -38,7 +38,14 @@ export class State { const { stateName, onEnterEvents } = this.props; return { stateName, - onEnter: onEnterEvents && { events: onEnterEvents }, + onEnter: onEnterEvents && { events: getEventJson(onEnterEvents) }, }; } + + /** + * returns true if this state has at least one condition via events + */ + public hasCondition(): boolean { + return this.props.onEnterEvents?.some(event => event.condition) ?? false; + } } 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 7077c47af326b..bca402564af6f 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -10,6 +10,10 @@ test('Default property', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.fromString('test-eventCondition'), + }], }), }); @@ -19,6 +23,12 @@ test('Default property', () => { InitialStateName: 'test-state', States: [{ StateName: 'test-state', + OnEnter: { + Events: [{ + EventName: 'test-eventName', + Condition: 'test-eventCondition', + }], + }, }], }, RoleArn: { @@ -43,6 +53,10 @@ test('can get detector model name', () => { const detectorModel = new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.fromString('test-eventCondition'), + }], }), }); @@ -66,7 +80,13 @@ test('can set physical name', () => { // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { detectorModelName: 'test-detector-model', - initialState: new iotevents.State({ stateName: 'test-state' }), + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.fromString('test-eventCondition'), + }], + }), }); // THEN @@ -75,17 +95,22 @@ test('can set physical name', () => { }); }); -test('can set onEnterEvents', () => { +test('can set multiple events to State', () => { const stack = new cdk.Stack(); // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ - eventName: 'test-eventName', - condition: 'test-eventCondition', - }], + onEnterEvents: [ + { + eventName: 'test-eventName1', + condition: iotevents.Expression.fromString('test-eventCondition'), + }, + { + eventName: 'test-eventName2', + }, + ], }), }); @@ -95,10 +120,13 @@ test('can set onEnterEvents', () => { States: [ Match.objectLike({ OnEnter: { - Events: [{ - EventName: 'test-eventName', - Condition: 'test-eventCondition', - }], + Events: [ + { + EventName: 'test-eventName1', + Condition: 'test-eventCondition', + }, + { EventName: 'test-eventName2' }, + ], }, }), ], @@ -113,7 +141,13 @@ test('can set role', () => { const role = iam.Role.fromRoleArn(stack, 'test-role', 'arn:aws:iam::123456789012:role/ForTest'); new iotevents.DetectorModel(stack, 'MyDetectorModel', { role, - initialState: new iotevents.State({ stateName: 'test-state' }), + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.fromString('test-eventCondition'), + }], + }), }); // THEN @@ -134,3 +168,160 @@ test('can import a DetectorModel by detectorModelName', () => { detectorModelName: detectorModelName, }); }); + +test('cannot create without condition', () => { + const stack = new cdk.Stack(); + + expect(() => { + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + }], + }), + }); + }).toThrow('Detector Model must use at least one Input in a condition.'); +}); + +test('cannot create without event', () => { + const stack = new cdk.Stack(); + + expect(() => { + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + }), + }); + }).toThrow('Detector Model must use at least one Input in a condition.'); +}); + +describe('Expression', () => { + test('currentInput', () => { + const stack = new cdk.Stack(); + + // WHEN + const input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.currentInput(input), + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [Match.objectLike({ + Condition: 'currentInput("test-input")', + })], + }, + }), + ], + }, + }); + }); + + test('inputAttribute', () => { + const stack = new cdk.Stack(); + + // WHEN + const input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.inputAttribute(input, 'json.path'), + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [Match.objectLike({ + Condition: '$input.test-input.json.path', + })], + }, + }), + ], + }, + }); + }); + + test('eq', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.eq( + iotevents.Expression.fromString('"aaa"'), + iotevents.Expression.fromString('"bbb"'), + ), + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [Match.objectLike({ + Condition: '"aaa" == "bbb"', + })], + }, + }), + ], + }, + }); + }); + + test('eq', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.DetectorModel(stack, 'MyDetectorModel', { + initialState: new iotevents.State({ + stateName: 'test-state', + onEnterEvents: [{ + eventName: 'test-eventName', + condition: iotevents.Expression.and( + iotevents.Expression.fromString('true'), + iotevents.Expression.fromString('false'), + ), + }], + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', { + DetectorModelDefinition: { + States: [ + Match.objectLike({ + OnEnter: { + Events: [Match.objectLike({ + Condition: 'true && false', + })], + }, + }), + ], + }, + }); + }); +}); 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 517abb207d2f8..f97d40bc6da25 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 @@ -48,7 +48,11 @@ { "Ref": "MyInput08947B23" }, - "\")" + "\") && $input.", + { + "Ref": "MyInput08947B23" + }, + ".payload.temperature == 31.5" ] ] }, 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 2a65816640bee..50eac24cbd336 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -16,7 +16,14 @@ class TestStack extends cdk.Stack { stateName: 'online', onEnterEvents: [{ eventName: 'test-event', - condition: `currentInput("${input.inputName}")`, + // meaning `condition: 'currentInput("test_input") && $input.test_input.payload.temperature == 31.5'` + condition: iotevents.Expression.and( + iotevents.Expression.currentInput(input), + iotevents.Expression.eq( + iotevents.Expression.inputAttribute(input, 'payload.temperature'), + iotevents.Expression.fromString('31.5'), + ), + ), }], }); From 8f82cbb88cb0038bae6b66ef0ecaf0cb9ea00f8e Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 09:07:30 +0900 Subject: [PATCH 06/24] Update packages/@aws-cdk/aws-iotevents/README.md Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 0270792af3be9..8ed90a8511287 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -42,7 +42,7 @@ import * as iotevents from '@aws-cdk/aws-iotevents'; ## `DetectorModel` -The following example creates an AWS IoT Events detector dodel to your stack. +The following example creates an AWS IoT Events detector model to your stack. The detector model need a reference to at least one AWS IoT Events input. AWS IoT Events input enable that the detector can get MQTT payload values from IoT Core rules. From fceea45114c3f5ff7080fb974af2053becf7c21e Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 09:08:49 +0900 Subject: [PATCH 07/24] Update packages/@aws-cdk/aws-iotevents/README.md Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 8ed90a8511287..499dbcc4ccda7 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -44,7 +44,7 @@ import * as iotevents from '@aws-cdk/aws-iotevents'; The following example creates an AWS IoT Events detector model to your stack. The detector model need a reference to at least one AWS IoT Events input. -AWS IoT Events input enable that the detector can get MQTT payload values from IoT Core rules. +AWS IoT Events inputs enable the detector to get MQTT payload values from IoT Core rules. ```ts import * as iotevents from '@aws-cdk/aws-iotevents'; From 8ae95cd38e3bea38320caa2ab3ec9069acda2476 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 09:09:09 +0900 Subject: [PATCH 08/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index cbc33b09a2896..d00482f45dfdf 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -34,7 +34,7 @@ export interface DetectorModelProps { /** * The role that grants permission to AWS IoT Events to perform its operations. * - * @default - a role will be created with default permissions. + * @default - a role will be created with default permissions */ readonly role?: iam.IRole; } From ff69d77841f15fa7578135c621346b03aea5c36d Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:30:18 +0900 Subject: [PATCH 09/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index d00482f45dfdf..61e48776a2b49 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -47,10 +47,9 @@ export class DetectorModel extends Resource implements IDetectorModel { * Import an existing detector model */ public static fromDetectorModelName(scope: Construct, id: string, detectorModelName: string): IDetectorModel { - class Import extends Resource implements IDetectorModel { + return new class extends Resource implements IDetectorModel { public readonly detectorModelName = detectorModelName; - } - return new Import(scope, id); + }(scope, id); } public readonly detectorModelName: string; From d1972565b53c6da5b57b86359d32db00e2f6d4f8 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:39:31 +0900 Subject: [PATCH 10/24] Update packages/@aws-cdk/aws-iotevents/lib/event.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts index c8a67b661120d..2c841026a406c 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/event.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -13,7 +13,7 @@ export interface Event { /** * The Boolean expression that, when TRUE, causes the actions to be performed. * - * @default None - Defaults to perform the actions always. + * @default - none (the actions are always executed) */ readonly condition?: Expression; } From f3511b2d9be90ab7792474d1094c53f63e44fe3a Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:40:20 +0900 Subject: [PATCH 11/24] Update packages/@aws-cdk/aws-iotevents/lib/event.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts index 2c841026a406c..5965d0d54ab8b 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/event.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -6,7 +6,7 @@ import { CfnDetectorModel } from './iotevents.generated'; */ export interface Event { /** - * The name of the event + * The name of the event. */ readonly eventName: string; From e5baa257b5764f670c0e1b67bc8863aa4fd06071 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:41:28 +0900 Subject: [PATCH 12/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 61e48776a2b49..8e1cd97b0fb36 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -9,7 +9,8 @@ import { State } from './state'; */ export interface IDetectorModel extends IResource { /** - * The name of the detector model + * The name of the detector model. + * * @attribute */ readonly detectorModelName: string; From 581ddefa168e0096a471dd92b2d9dfcd4ec630d3 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:41:51 +0900 Subject: [PATCH 13/24] Update packages/@aws-cdk/aws-iotevents/lib/state.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index ac6fec5262e0c..978778fba4282 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -13,7 +13,7 @@ export interface StateProps { /** * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE` * - * @default None + * @default - no actions will be performed when the state is entered */ readonly onEnterEvents?: Event[]; } From 50c183cdf60e1735b347e71671128900812e2c7b Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:44:00 +0900 Subject: [PATCH 14/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 8e1cd97b0fb36..8b54630dd699e 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -21,7 +21,7 @@ export interface IDetectorModel extends IResource { */ export interface DetectorModelProps { /** - * The name of the detector model + * The name of the detector model. * * @default - CloudFormation will generate a unique name of the detector model */ From 971d5c41e10b8dfcb3b75e3ddcba76f63b23fe38 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:44:20 +0900 Subject: [PATCH 15/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 8b54630dd699e..4e88a2efdd4cd 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -45,7 +45,7 @@ export interface DetectorModelProps { */ export class DetectorModel extends Resource implements IDetectorModel { /** - * Import an existing detector model + * Import an existing detector model. */ public static fromDetectorModelName(scope: Construct, id: string, detectorModelName: string): IDetectorModel { return new class extends Resource implements IDetectorModel { From fbfe0286940af173dafa5a99b86da065ab79ed57 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:44:57 +0900 Subject: [PATCH 16/24] Update packages/@aws-cdk/aws-iotevents/lib/detector-model.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index 4e88a2efdd4cd..a8de2af723462 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -61,7 +61,7 @@ export class DetectorModel extends Resource implements IDetectorModel { }); if (!props.initialState.hasCondition()) { - throw new Error('Detector Model must use at least one Input in a condition.'); + throw new Error('Detector Model must have at least one Input with a condition'); } const role = props.role ?? new iam.Role(this, 'DetectorModelRole', { From 0b6600d046f2aaa6d9f5b047be9e94ccd838c493 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:45:19 +0900 Subject: [PATCH 17/24] Update packages/@aws-cdk/aws-iotevents/lib/expression.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/expression.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts index 8217bcf69062a..6fe1828fb8b32 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/expression.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -63,7 +63,7 @@ class StringExpression extends Expression { class BinaryOperationExpression extends Expression { constructor( private readonly left: Expression, - private readonly operater: string, + private readonly operator: string, private readonly right: Expression, ) { super(); From 18e86d02a04f3b8e498dbc5cc6cfe7045da9a56b Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:45:57 +0900 Subject: [PATCH 18/24] Update packages/@aws-cdk/aws-iotevents/lib/state.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 978778fba4282..e70ee6f2652e0 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -6,7 +6,7 @@ import { CfnDetectorModel } from './iotevents.generated'; */ export interface StateProps { /** - * The name of the state + * The name of the state. */ readonly stateName: string; From 9744d78be8c96ca62b7bc463a9ac5fa073a90989 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Fri, 21 Jan 2022 10:46:22 +0900 Subject: [PATCH 19/24] Update packages/@aws-cdk/aws-iotevents/lib/state.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/lib/state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index e70ee6f2652e0..809efbd1a15b3 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -11,7 +11,7 @@ export interface StateProps { readonly stateName: string; /** - * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE` + * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE`. * * @default - no actions will be performed when the state is entered */ From d89d0a0b47eb34b3ed4bf94a926fa8db4f0a04bb Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Fri, 21 Jan 2022 13:15:25 +0900 Subject: [PATCH 20/24] fix tests --- packages/@aws-cdk/aws-iotevents/lib/expression.ts | 2 +- packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/expression.ts b/packages/@aws-cdk/aws-iotevents/lib/expression.ts index 6fe1828fb8b32..27fdf069c1b9f 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/expression.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/expression.ts @@ -70,6 +70,6 @@ class BinaryOperationExpression extends Expression { } public evaluate() { - return `${this.left.evaluate()} ${this.operater} ${this.right.evaluate()}`; + return `${this.left.evaluate()} ${this.operator} ${this.right.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 bca402564af6f..b8f8531e499dd 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -181,7 +181,7 @@ test('cannot create without condition', () => { }], }), }); - }).toThrow('Detector Model must use at least one Input in a condition.'); + }).toThrow('Detector Model must have at least one Input with a condition'); }); test('cannot create without event', () => { @@ -193,7 +193,7 @@ test('cannot create without event', () => { stateName: 'test-state', }), }); - }).toThrow('Detector Model must use at least one Input in a condition.'); + }).toThrow('Detector Model must have at least one Input with a condition'); }); describe('Expression', () => { From 6ff671e393fe6fe3b2b01fecf714ecb985f54c2f Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Fri, 21 Jan 2022 16:43:10 +0900 Subject: [PATCH 21/24] address comments --- .../aws-iotevents/lib/detector-model.ts | 2 +- packages/@aws-cdk/aws-iotevents/lib/event.ts | 10 ------- packages/@aws-cdk/aws-iotevents/lib/state.ts | 15 ++++++++-- .../aws-iotevents/test/detector-model.test.ts | 28 ++++--------------- .../test/integ.detector-model.ts | 5 ++-- 5 files changed, 21 insertions(+), 39 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index a8de2af723462..a34b42ea70100 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -72,7 +72,7 @@ export class DetectorModel extends Resource implements IDetectorModel { detectorModelName: this.physicalName, detectorModelDefinition: { initialStateName: props.initialState.stateName, - states: [props.initialState.toStateJson()], + states: [props.initialState._toStateJson()], }, roleArn: role.roleArn, }); diff --git a/packages/@aws-cdk/aws-iotevents/lib/event.ts b/packages/@aws-cdk/aws-iotevents/lib/event.ts index 5965d0d54ab8b..610469db9c32c 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/event.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/event.ts @@ -1,5 +1,4 @@ import { Expression } from './expression'; -import { CfnDetectorModel } from './iotevents.generated'; /** * Specifies the actions to be performed when the condition evaluates to TRUE. @@ -17,12 +16,3 @@ export interface Event { */ readonly condition?: Expression; } - -export function getEventJson(events: Event[]): CfnDetectorModel.EventProperty[] { - return events.map(e => { - return { - eventName: e.eventName, - condition: e.condition?.evaluate(), - }; - }); -} diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 809efbd1a15b3..0f88f04abdd72 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -1,4 +1,4 @@ -import { Event, getEventJson } from './event'; +import { Event } from './event'; import { CfnDetectorModel } from './iotevents.generated'; /** @@ -33,8 +33,10 @@ export class State { /** * Return the state property JSON + * + * @internal */ - public toStateJson(): CfnDetectorModel.StateProperty { + public _toStateJson(): CfnDetectorModel.StateProperty { const { stateName, onEnterEvents } = this.props; return { stateName, @@ -49,3 +51,12 @@ export class State { return this.props.onEnterEvents?.some(event => event.condition) ?? false; } } + +function getEventJson(events: Event[]): CfnDetectorModel.EventProperty[] { + return events.map(e => { + return { + eventName: e.eventName, + condition: e.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 b8f8531e499dd..69675b3421f2f 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -3,9 +3,12 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as iotevents from '../lib'; -test('Default property', () => { - const stack = new cdk.Stack(); +let stack: cdk.Stack; +beforeEach(() => { + stack = new cdk.Stack(); +}); +test('Default property', () => { // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -48,7 +51,6 @@ test('Default property', () => { }); test('can get detector model name', () => { - const stack = new cdk.Stack(); // GIVEN const detectorModel = new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -75,8 +77,6 @@ test('can get detector model name', () => { }); test('can set physical name', () => { - const stack = new cdk.Stack(); - // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { detectorModelName: 'test-detector-model', @@ -96,8 +96,6 @@ test('can set physical name', () => { }); test('can set multiple events to State', () => { - const stack = new cdk.Stack(); - // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -135,8 +133,6 @@ test('can set multiple events to State', () => { }); test('can set role', () => { - const stack = new cdk.Stack(); - // WHEN const role = iam.Role.fromRoleArn(stack, 'test-role', 'arn:aws:iam::123456789012:role/ForTest'); new iotevents.DetectorModel(stack, 'MyDetectorModel', { @@ -157,8 +153,6 @@ test('can set role', () => { }); test('can import a DetectorModel by detectorModelName', () => { - const stack = new cdk.Stack(); - // WHEN const detectorModelName = 'detector-model-name'; const detectorModel = iotevents.DetectorModel.fromDetectorModelName(stack, 'ExistingDetectorModel', detectorModelName); @@ -170,8 +164,6 @@ test('can import a DetectorModel by detectorModelName', () => { }); test('cannot create without condition', () => { - const stack = new cdk.Stack(); - expect(() => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -185,8 +177,6 @@ test('cannot create without condition', () => { }); test('cannot create without event', () => { - const stack = new cdk.Stack(); - expect(() => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -198,8 +188,6 @@ test('cannot create without event', () => { describe('Expression', () => { test('currentInput', () => { - const stack = new cdk.Stack(); - // WHEN const input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); new iotevents.DetectorModel(stack, 'MyDetectorModel', { @@ -229,8 +217,6 @@ describe('Expression', () => { }); test('inputAttribute', () => { - const stack = new cdk.Stack(); - // WHEN const input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input'); new iotevents.DetectorModel(stack, 'MyDetectorModel', { @@ -260,8 +246,6 @@ describe('Expression', () => { }); test('eq', () => { - const stack = new cdk.Stack(); - // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ @@ -293,8 +277,6 @@ describe('Expression', () => { }); test('eq', () => { - const stack = new cdk.Stack(); - // WHEN new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ 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 50eac24cbd336..59a1afd96274f 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -1,8 +1,6 @@ import * as cdk from '@aws-cdk/core'; import * as iotevents from '../lib'; -const app = new cdk.App(); - class TestStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); @@ -34,5 +32,6 @@ class TestStack extends cdk.Stack { } } -new TestStack(app, 'test-stack'); +const app = new cdk.App(); +new TestStack(app, 'detector-model-test-stack'); app.synth(); From 78fc88c67e0e7d63d6c7ddb98cf50f3f3ba4d02b Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Fri, 21 Jan 2022 21:53:47 +0900 Subject: [PATCH 22/24] fix JSDoc of onEnter and rename --- packages/@aws-cdk/aws-iotevents/README.md | 2 +- packages/@aws-cdk/aws-iotevents/lib/state.ts | 13 ++++++------ .../aws-iotevents/test/detector-model.test.ts | 20 +++++++++---------- .../test/integ.detector-model.ts | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index 499dbcc4ccda7..fe071d7baecc6 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -56,7 +56,7 @@ const input = new iotevents.Input(this, 'MyInput', { const onlineState = new iotevents.State({ stateName: 'online', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-event', condition: iotevents.Expression.currentInput(input), }], diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index 0f88f04abdd72..e11e7e6e4f502 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -11,11 +11,12 @@ export interface StateProps { readonly stateName: string; /** - * Specifies the actions that are performed when the state is entered and the `condition` is `TRUE`. + * 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. * - * @default - no actions will be performed when the state is entered + * @default - events on enter will not be set */ - readonly onEnterEvents?: Event[]; + readonly onEnter?: Event[]; } /** @@ -37,10 +38,10 @@ export class State { * @internal */ public _toStateJson(): CfnDetectorModel.StateProperty { - const { stateName, onEnterEvents } = this.props; + const { stateName, onEnter } = this.props; return { stateName, - onEnter: onEnterEvents && { events: getEventJson(onEnterEvents) }, + onEnter: onEnter && { events: getEventJson(onEnter) }, }; } @@ -48,7 +49,7 @@ export class State { * returns true if this state has at least one condition via events */ public hasCondition(): boolean { - return this.props.onEnterEvents?.some(event => event.condition) ?? false; + return this.props.onEnter?.some(event => event.condition) ?? false; } } 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 69675b3421f2f..69187a8c81325 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -13,7 +13,7 @@ test('Default property', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.fromString('test-eventCondition'), }], @@ -55,7 +55,7 @@ test('can get detector model name', () => { const detectorModel = new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.fromString('test-eventCondition'), }], @@ -82,7 +82,7 @@ test('can set physical name', () => { detectorModelName: 'test-detector-model', initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.fromString('test-eventCondition'), }], @@ -100,7 +100,7 @@ test('can set multiple events to State', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [ + onEnter: [ { eventName: 'test-eventName1', condition: iotevents.Expression.fromString('test-eventCondition'), @@ -139,7 +139,7 @@ test('can set role', () => { role, initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.fromString('test-eventCondition'), }], @@ -168,7 +168,7 @@ test('cannot create without condition', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', }], }), @@ -193,7 +193,7 @@ describe('Expression', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.currentInput(input), }], @@ -222,7 +222,7 @@ describe('Expression', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.inputAttribute(input, 'json.path'), }], @@ -250,7 +250,7 @@ describe('Expression', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.eq( iotevents.Expression.fromString('"aaa"'), @@ -281,7 +281,7 @@ describe('Expression', () => { new iotevents.DetectorModel(stack, 'MyDetectorModel', { initialState: new iotevents.State({ stateName: 'test-state', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-eventName', condition: iotevents.Expression.and( iotevents.Expression.fromString('true'), 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 59a1afd96274f..8eeef110d5b8a 100644 --- a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -12,7 +12,7 @@ class TestStack extends cdk.Stack { const onlineState = new iotevents.State({ stateName: 'online', - onEnterEvents: [{ + onEnter: [{ eventName: 'test-event', // meaning `condition: 'currentInput("test_input") && $input.test_input.payload.temperature == 31.5'` condition: iotevents.Expression.and( From 5506cb5af270c1b51f87a1c85c5a19853a533b05 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Sat, 22 Jan 2022 08:48:20 +0900 Subject: [PATCH 23/24] Update packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts Co-authored-by: Adam Ruka --- packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 69187a8c81325..d6fbadd5baf9b 100644 --- a/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/detector-model.test.ts @@ -123,7 +123,9 @@ test('can set multiple events to State', () => { EventName: 'test-eventName1', Condition: 'test-eventCondition', }, - { EventName: 'test-eventName2' }, + { + EventName: 'test-eventName2', + }, ], }, }), From 087bb42523c55825053823e210bb1707925616c6 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Sat, 22 Jan 2022 08:52:52 +0900 Subject: [PATCH 24/24] address comments --- packages/@aws-cdk/aws-iotevents/lib/detector-model.ts | 2 +- packages/@aws-cdk/aws-iotevents/lib/state.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts index a34b42ea70100..2a5d270fb0cde 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/detector-model.ts @@ -60,7 +60,7 @@ export class DetectorModel extends Resource implements IDetectorModel { physicalName: props.detectorModelName, }); - if (!props.initialState.hasCondition()) { + if (!props.initialState._onEnterEventsHaveAtLeastOneCondition()) { throw new Error('Detector Model must have at least one Input with a condition'); } diff --git a/packages/@aws-cdk/aws-iotevents/lib/state.ts b/packages/@aws-cdk/aws-iotevents/lib/state.ts index e11e7e6e4f502..e16d911d60004 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/state.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/state.ts @@ -47,8 +47,10 @@ export class State { /** * returns true if this state has at least one condition via events + * + * @internal */ - public hasCondition(): boolean { + public _onEnterEventsHaveAtLeastOneCondition(): boolean { return this.props.onEnter?.some(event => event.condition) ?? false; } }