diff --git a/packages/@aws-cdk/aws-location/README.md b/packages/@aws-cdk/aws-location/README.md index 091a3b1f8f687..9221ecf549270 100644 --- a/packages/@aws-cdk/aws-location/README.md +++ b/packages/@aws-cdk/aws-location/README.md @@ -9,31 +9,49 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts nofixture -import * as location from '@aws-cdk/aws-location'; -``` - - +Amazon Location Service lets you add location data and functionality to applications, which +includes capabilities such as maps, points of interest, geocoding, routing, geofences, and +tracking. Amazon Location provides location-based services (LBS) using high-quality data from +global, trusted providers Esri and HERE. With affordable data, tracking and geofencing +capabilities, and built-in metrics for health monitoring, you can build sophisticated +location-enabled applications. -There are no official hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. Here are some suggestions on how to proceed: +## Place Index -- Search [Construct Hub for Location construct libraries](https://constructs.dev/search?q=location) -- Use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, in the same way you would use [the CloudFormation AWS::Location resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Location.html) directly. +A key function of Amazon Location Service is the ability to search the geolocation information. +Amazon Location provides this functionality via the Place index resource. The place index includes +which [data provider](https://docs.aws.amazon.com/location/latest/developerguide/what-is-data-provider.html) +to use for the search. +To create a place index, define a `PlaceIndex`: - - -There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. -However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. +```ts +new location.PlaceIndex(this, 'PlaceIndex', { + placeIndexName: 'MyPlaceIndex', // optional, defaults to a generated name + dataSource: location.DataSource.HERE, // optional, defaults to Esri +}); +``` -For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Location.html). +Use the `grant()` or `grantSearch()` method to grant the given identity permissions to perform actions +on the place index: -(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and submit an RFC if you are interested in contributing to this construct library.) +```ts +declare const role: iam.Role; - +const placeIndex = new location.PlaceIndex(this, 'PlaceIndex'); +placeIndex.grantSearch(role); +``` diff --git a/packages/@aws-cdk/aws-location/lib/index.ts b/packages/@aws-cdk/aws-location/lib/index.ts index 83c72abef42d3..d281a498ac7cc 100644 --- a/packages/@aws-cdk/aws-location/lib/index.ts +++ b/packages/@aws-cdk/aws-location/lib/index.ts @@ -1,2 +1,4 @@ +export * from './place-index'; + // AWS::Location CloudFormation Resources: export * from './location.generated'; diff --git a/packages/@aws-cdk/aws-location/lib/place-index.ts b/packages/@aws-cdk/aws-location/lib/place-index.ts new file mode 100644 index 0000000000000..767ce402a42c0 --- /dev/null +++ b/packages/@aws-cdk/aws-location/lib/place-index.ts @@ -0,0 +1,209 @@ +import * as iam from '@aws-cdk/aws-iam'; +import { ArnFormat, IResource, Lazy, Names, Resource, Stack, Token } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnPlaceIndex } from './location.generated'; + +/** + * A Place Index + */ +export interface IPlaceIndex extends IResource { + /** + * The name of the place index + * + * @attribute + */ + readonly placeIndexName: string; + + /** + * The Amazon Resource Name (ARN) of the place index resource + * + * @attribute Arn,IndexArn + */ + readonly placeIndexArn: string; +} + +/** + * Properties for a place index + */ +export interface PlaceIndexProps { + /** + * A name for the place index + * + * @default - A name is automatically generated + */ + readonly placeIndexName?: string; + + /** + * Data source for the place index + * + * @default DataSource.ESRI + */ + readonly dataSource?: DataSource; + + /** + * Intend use for the results of an operation + * + * @default IntendedUse.SINGLE_USE + */ + readonly intendedUse?: IntendedUse; + + /** + * A description for the place index + * + * @default - no description + */ + readonly description?: string; +} + +/** + * Data source for a place index + */ +export enum DataSource { + /** + * Esri + * + * @see https://docs.aws.amazon.com/location/latest/developerguide/esri.html + */ + ESRI = 'Esri', + + /** + * HERE + * + * @see https://docs.aws.amazon.com/location/latest/developerguide/HERE.html + */ + HERE = 'Here' +} + +/** + * Intend use for the results of an operation + */ +export enum IntendedUse { + /** + * The results won't be stored + */ + SINGLE_USE = 'SingleUse', + + /** + * The result can be cached or stored in a database + */ + STORAGE = 'Storage' +} + +abstract class PlaceIndexBase extends Resource implements IPlaceIndex { + public abstract readonly placeIndexName: string; + public abstract readonly placeIndexArn: string; + + /** + * Grant the given principal identity permissions to perform the actions on this place index. + */ + public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee: grantee, + actions: actions, + resourceArns: [this.placeIndexArn], + }); + } + + /** + * Grant the given identity permissions to search using this index + */ + public grantSearch(grantee: iam.IGrantable): iam.Grant { + return this.grant(grantee, + 'geo:SearchPlaceIndexForPosition', + 'geo:SearchPlaceIndexForSuggestions', + 'geo:SearchPlaceIndexForText', + ); + } +} + +/** + * A Place Index + * + * @see https://docs.aws.amazon.com/location/latest/developerguide/places-concepts.html + */ +export class PlaceIndex extends PlaceIndexBase { + /** + * Use an existing place index by name + */ + public static fromPlaceIndexName(scope: Construct, id: string, placeIndexName: string): IPlaceIndex { + const placeIndexArn = Stack.of(scope).formatArn({ + service: 'geo', + resource: 'place-index', + resourceName: placeIndexName, + }); + + return PlaceIndex.fromPlaceIndexArn(scope, id, placeIndexArn); + } + + /** + * Use an existing place index by ARN + */ + public static fromPlaceIndexArn(scope: Construct, id: string, placeIndexArn: string): IPlaceIndex { + const parsedArn = Stack.of(scope).splitArn(placeIndexArn, ArnFormat.SLASH_RESOURCE_NAME); + + if (!parsedArn.resourceName) { + throw new Error(`Place Index Arn ${placeIndexArn} does not have a resource name.`); + } + + class Import extends PlaceIndexBase { + public readonly placeIndexName = parsedArn.resourceName!; + public readonly placeIndexArn = placeIndexArn; + } + + return new Import(scope, id, { + account: parsedArn.account, + region: parsedArn.region, + }); + } + + public readonly placeIndexName: string; + + public readonly placeIndexArn: string; + + /** + * The timestamp for when the place index resource was created in ISO 8601 forma + * + * @attribute + */ + public readonly placeIndexCreateTime: string; + + /** + * The timestamp for when the place index resource was last updated in ISO 8601 format + * + * @attribute + */ + public readonly placeIndexUpdateTime: string; + + + constructor(scope: Construct, id: string, props: PlaceIndexProps = {}) { + if (props.placeIndexName && !Token.isUnresolved(props.placeIndexName) && !/^[-.\w]{1,100}$/.test(props.placeIndexName)) { + throw new Error(`Invalid place index name. The place index name must be between 1 and 100 characters and contain only alphanumeric characters, hyphens, periods and underscores. Received: ${props.placeIndexName}`); + } + + super(scope, id, { + physicalName: props.placeIndexName ?? Lazy.string({ produce: () => this.generateUniqueId() }), + }); + + const placeIndex = new CfnPlaceIndex(this, 'Resource', { + indexName: this.physicalName, + dataSource: props.dataSource ?? DataSource.ESRI, + dataSourceConfiguration: props.intendedUse + ? { intendedUse: props.intendedUse } + : undefined, + description: props.description, + }); + + this.placeIndexName = placeIndex.ref; + this.placeIndexArn = placeIndex.attrArn; + this.placeIndexCreateTime = placeIndex.attrCreateTime; + this.placeIndexUpdateTime = placeIndex.attrUpdateTime; + } + + private generateUniqueId(): string { + const name = Names.uniqueId(this); + if (name.length > 100) { + return name.substring(0, 50) + name.substring(name.length - 50); + } + return name; + } +} diff --git a/packages/@aws-cdk/aws-location/package.json b/packages/@aws-cdk/aws-location/package.json index 1a2d3defc5caf..a7157e8e78847 100644 --- a/packages/@aws-cdk/aws-location/package.json +++ b/packages/@aws-cdk/aws-location/package.json @@ -85,23 +85,27 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/integ-runner": "0.0.0", + "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.5.2" }, "dependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "constructs": "^10.0.0" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "constructs": "^10.0.0" }, "engines": { "node": ">= 14.15.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-location/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-location/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..107841df19d1e --- /dev/null +++ b/packages/@aws-cdk/aws-location/rosetta/default.ts-fixture @@ -0,0 +1,13 @@ +// Fixture with packages imported, but nothing else +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as location from '@aws-cdk/aws-location'; +import * as iam from '@aws-cdk/aws-iam'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.assets.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.assets.json new file mode 100644 index 0000000000000..1c758b7b305ec --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "PlaceIndexTestDefaultTestDeployAssert3F96C508.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.template.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/PlaceIndexTestDefaultTestDeployAssert3F96C508.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.assets.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.assets.json new file mode 100644 index 0000000000000..92d001c5e2482 --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "94bd94a7c3b98a6be66d32f390a66e2768617691c6d6f2bff2884647475cdaf4": { + "source": { + "path": "cdk-integ-location-place-index.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "94bd94a7c3b98a6be66d32f390a66e2768617691c6d6f2bff2884647475cdaf4.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.template.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.template.json new file mode 100644 index 0000000000000..c8e0ca466e94d --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk-integ-location-place-index.template.json @@ -0,0 +1,45 @@ +{ + "Resources": { + "PlaceIndex21B3574E": { + "Type": "AWS::Location::PlaceIndex", + "Properties": { + "DataSource": "Esri", + "IndexName": "cdkinteglocationplaceindexPlaceIndex21A03EAC" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk.out b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/integ.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/integ.json new file mode 100644 index 0000000000000..b8d0815ec42db --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "PlaceIndexTest/DefaultTest": { + "stacks": [ + "cdk-integ-location-place-index" + ], + "assertionStack": "PlaceIndexTest/DefaultTest/DeployAssert", + "assertionStackName": "PlaceIndexTestDefaultTestDeployAssert3F96C508" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/manifest.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/manifest.json new file mode 100644 index 0000000000000..8b8b90d022243 --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/manifest.json @@ -0,0 +1,111 @@ +{ + "version": "21.0.0", + "artifacts": { + "cdk-integ-location-place-index.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdk-integ-location-place-index.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdk-integ-location-place-index": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdk-integ-location-place-index.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/94bd94a7c3b98a6be66d32f390a66e2768617691c6d6f2bff2884647475cdaf4.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdk-integ-location-place-index.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "cdk-integ-location-place-index.assets" + ], + "metadata": { + "/cdk-integ-location-place-index/PlaceIndex/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PlaceIndex21B3574E" + } + ], + "/cdk-integ-location-place-index/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-integ-location-place-index/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-integ-location-place-index" + }, + "PlaceIndexTestDefaultTestDeployAssert3F96C508.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PlaceIndexTestDefaultTestDeployAssert3F96C508.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PlaceIndexTestDefaultTestDeployAssert3F96C508": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PlaceIndexTestDefaultTestDeployAssert3F96C508.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PlaceIndexTestDefaultTestDeployAssert3F96C508.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "PlaceIndexTestDefaultTestDeployAssert3F96C508.assets" + ], + "metadata": { + "/PlaceIndexTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PlaceIndexTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PlaceIndexTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/tree.json b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/tree.json new file mode 100644 index 0000000000000..c498288355b3a --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.js.snapshot/tree.json @@ -0,0 +1,126 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "cdk-integ-location-place-index": { + "id": "cdk-integ-location-place-index", + "path": "cdk-integ-location-place-index", + "children": { + "PlaceIndex": { + "id": "PlaceIndex", + "path": "cdk-integ-location-place-index/PlaceIndex", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-integ-location-place-index/PlaceIndex/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Location::PlaceIndex", + "aws:cdk:cloudformation:props": { + "dataSource": "Esri", + "indexName": "cdkinteglocationplaceindexPlaceIndex21A03EAC" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-location.CfnPlaceIndex", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-location.PlaceIndex", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-integ-location-place-index/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-integ-location-place-index/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PlaceIndexTest": { + "id": "PlaceIndexTest", + "path": "PlaceIndexTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PlaceIndexTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PlaceIndexTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.140" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PlaceIndexTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PlaceIndexTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PlaceIndexTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.140" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-location/test/integ.place-index.ts b/packages/@aws-cdk/aws-location/test/integ.place-index.ts new file mode 100644 index 0000000000000..738f5608e451c --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/integ.place-index.ts @@ -0,0 +1,20 @@ +import { App, Stack } from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { Construct } from 'constructs'; +import { PlaceIndex } from '../lib'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + new PlaceIndex(this, 'PlaceIndex'); + } +} + +const app = new App(); + +new integ.IntegTest(app, 'PlaceIndexTest', { + testCases: [new TestStack(app, 'cdk-integ-location-place-index')], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-location/test/location.test.ts b/packages/@aws-cdk/aws-location/test/location.test.ts deleted file mode 100644 index 465c7bdea0693..0000000000000 --- a/packages/@aws-cdk/aws-location/test/location.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assertions'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); diff --git a/packages/@aws-cdk/aws-location/test/place-index.test.ts b/packages/@aws-cdk/aws-location/test/place-index.test.ts new file mode 100644 index 0000000000000..e44cc79db7f9d --- /dev/null +++ b/packages/@aws-cdk/aws-location/test/place-index.test.ts @@ -0,0 +1,85 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import { Stack } from '@aws-cdk/core'; +import { DataSource, IntendedUse, PlaceIndex } from '../lib/place-index'; + +let stack: Stack; +beforeEach(() => { + stack = new Stack(); +}); + +test('create a place index', () => { + new PlaceIndex(stack, 'PlaceIndex'); + + Template.fromStack(stack).hasResourceProperties('AWS::Location::PlaceIndex', { + DataSource: 'Esri', + IndexName: 'PlaceIndex', + }); +}); + +test('throws with invalid name', () => { + expect(() => new PlaceIndex(stack, 'PlaceIndex', { + placeIndexName: 'inv@lid', + })).toThrow(/Invalid place index name/); +}); + +test('grant search actions', () => { + const placeIndex = new PlaceIndex(stack, 'PlaceIndex', { + dataSource: DataSource.HERE, + intendedUse: IntendedUse.STORAGE, + }); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('foo'), + }); + + placeIndex.grantSearch(role); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', Match.objectLike({ + PolicyDocument: Match.objectLike({ + Statement: [ + { + Action: [ + 'geo:SearchPlaceIndexForPosition', + 'geo:SearchPlaceIndexForSuggestions', + 'geo:SearchPlaceIndexForText', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'PlaceIndex21B3574E', + 'Arn', + ], + }, + }, + ], + }), + })); +}); + +test('import from arn', () => { + const placeIndexArn = stack.formatArn({ + service: 'geo', + resource: 'place-index', + resourceName: 'MyPlaceIndex', + }); + const placeIndex = PlaceIndex.fromPlaceIndexArn(stack, 'PlaceIndex', placeIndexArn); + + // THEN + expect(placeIndex.placeIndexName).toEqual('MyPlaceIndex'); + expect(placeIndex.placeIndexArn).toEqual(placeIndexArn); +}); + +test('import from name', () => { + // WHEN + const placeIndexName = 'MyPlaceIndex'; + const placeIndex = PlaceIndex.fromPlaceIndexName(stack, 'PlaceIndex', placeIndexName); + + // THEN + expect(placeIndex.placeIndexName).toEqual(placeIndexName); + expect(placeIndex.placeIndexArn).toEqual(stack.formatArn({ + service: 'geo', + resource: 'place-index', + resourceName: 'MyPlaceIndex', + })); +});