diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index 5631d73d2722d..2c310af40af88 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -449,6 +449,65 @@ new cloudwatch.Alarm(this, 'Alarm', { See: [Monitoring Using CloudWatch Metrics](https://docs.aws.amazon.com/gamelift/latest/developerguide/monitoring-cloudwatch.html) in the *Amazon GameLift Developer Guide*. +## Game session queue + +The game session queue is the primary mechanism for processing new game session +requests and locating available game servers to host them. Although it is +possible to request a new game session be hosted on specific fleet or location. + +The `GameSessionQueue` resource creates a placement queue that processes requests for +new game sessions. A queue uses FleetIQ algorithms to determine the best placement +locations and find an available game server, then prompts the game server to start a +new game session. Queues can have destinations (GameLift fleets or aliases), which +determine where the queue can place new game sessions. A queue can have destinations +with varied fleet type (Spot and On-Demand), instance type, and AWS Region. + +```ts +declare const fleet: gamelift.BuildFleet; +declare const alias: gamelift.Alias; + +const queue = new gamelift.GameSessionQueue(this, 'GameSessionQueue', { + gameSessionQueueName: 'my-queue-name', + destinations: [fleet] +}); +queue.addDestination(alias); +``` + +A more complex configuration can also be definied to override how FleetIQ algorithms prioritize game session placement in order to favour a destination based on `Cost`, `Latency`, `Destination order`or `Location`. + +```ts +declare const fleet: gamelift.BuildFleet; +declare const topic: sns.Topic; + +new gamelift.GameSessionQueue(this, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + customEventData: 'test-event-data', + allowedLocations: ['eu-west-1', 'eu-west-2'], + destinations: [fleet], + notificationTarget: topic, + playerLatencyPolicies: [{ + maximumIndividualPlayerLatency: Duration.millis(100), + policyDuration: Duration.seconds(300), + }], + priorityConfiguration: { + locationOrder: [ + 'eu-west-1', + 'eu-west-2', + ], + priorityOrder: [ + gamelift.PriorityType.LATENCY, + gamelift.PriorityType.COST, + gamelift.PriorityType.DESTINATION, + gamelift.PriorityType.LOCATION, + ], + }, + timeout: Duration.seconds(300), + }); +``` + +See [Setting up GameLift queues for game session placement](https://docs.aws.amazon.com/gamelift/latest/developerguide/realtime-script-uploading.html) +in the *Amazon GameLift Developer Guide*. + ## GameLift FleetIQ The GameLift FleetIQ solution is a game hosting layer that supplements the full diff --git a/packages/@aws-cdk/aws-gamelift/lib/alias.ts b/packages/@aws-cdk/aws-gamelift/lib/alias.ts index cdf61bd97c2a1..a95f0120aedee 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/alias.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/alias.ts @@ -1,12 +1,13 @@ import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { IFleet } from './fleet-base'; +import { IGameSessionQueueDestination } from './game-session-queue'; import { CfnAlias } from './gamelift.generated'; /** * Represents a Gamelift Alias for a Gamelift fleet destination. */ -export interface IAlias extends cdk.IResource { +export interface IAlias extends cdk.IResource, IGameSessionQueueDestination { /** * The Identifier of the alias. @@ -106,6 +107,12 @@ export abstract class AliasBase extends cdk.Resource implements IAlias { * The ARN of the alias */ public abstract readonly aliasArn: string; + /** + * The ARN to put into the destination field of a game session queue + */ + public get resourceArnForDestination() { + return this.aliasArn; + } } /** diff --git a/packages/@aws-cdk/aws-gamelift/lib/fleet-base.ts b/packages/@aws-cdk/aws-gamelift/lib/fleet-base.ts index bf76c6078db1c..9b98993b5d4f5 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/fleet-base.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/fleet-base.ts @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Alias, AliasOptions } from './alias'; +import { IGameSessionQueueDestination } from './game-session-queue'; import { GameLiftMetrics } from './gamelift-canned-metrics.generated'; import { CfnFleet } from './gamelift.generated'; @@ -140,7 +141,7 @@ export interface ResourceCreationLimitPolicy { /** * Represents a Gamelift fleet */ -export interface IFleet extends cdk.IResource, iam.IGrantable { +export interface IFleet extends cdk.IResource, iam.IGrantable, IGameSessionQueueDestination { /** * The Identifier of the fleet. * @@ -535,6 +536,13 @@ export abstract class FleetBase extends cdk.Resource implements IFleet { }).attachTo(this); } + /** + * The ARN to put into the destination field of a game session queue + */ + public get resourceArnForDestination() { + return this.fleetArn; + } + /** * Adds a remote locations to deploy additional instances to and manage as part of the fleet. * diff --git a/packages/@aws-cdk/aws-gamelift/lib/game-session-queue.ts b/packages/@aws-cdk/aws-gamelift/lib/game-session-queue.ts new file mode 100644 index 0000000000000..0d8167d1ae262 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/lib/game-session-queue.ts @@ -0,0 +1,471 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnGameSessionQueue } from './gamelift.generated'; + +/** + * Represents a game session queue destination + */ +export interface IGameSessionQueueDestination { + /** + * The ARN(s) to put into the destination field for a game session queue. + * + * This property is for cdk modules to consume only. You should not need to use this property. + * Instead, use dedicated identifier on each components. + */ + readonly resourceArnForDestination: string; +} + +/** + * Priority to condider when placing new game sessions + */ +export enum PriorityType { + /** + * FleetIQ prioritizes locations where the average player latency (provided in each game session request) is lowest. + */ + LATENCY = 'LATENCY', + /** + * FleetIQ prioritizes destinations with the lowest current hosting costs. Cost is evaluated based on the location, instance type, and fleet type (Spot or On-Demand) for each destination in the queue. + */ + COST = 'COST', + /** + * FleetIQ prioritizes based on the order that destinations are listed in the queue configuration. + */ + DESTINATION = 'DESTINATION', + /** + * FleetIQ prioritizes based on the provided order of locations, as defined in `LocationOrder` + */ + LOCATION = 'LOCATION' +} + +/** + * Custom prioritization settings for use by a game session queue when placing new game sessions with available game servers. + * When defined, this configuration replaces the default FleetIQ prioritization process, which is as follows: + * + * - If player latency data is included in a game session request, destinations and locations are prioritized first based on lowest average latency (1), then on lowest hosting cost (2), then on destination list order (3), and finally on location (alphabetical) (4). + * This approach ensures that the queue's top priority is to place game sessions where average player latency is lowest, and--if latency is the same--where the hosting cost is less, etc. + * + * - If player latency data is not included, destinations and locations are prioritized first on destination list order (1), and then on location (alphabetical) (2). + * This approach ensures that the queue's top priority is to place game sessions on the first destination fleet listed. If that fleet has multiple locations, the game session is placed on the first location (when listed alphabetically). + * + * Changing the priority order will affect how game sessions are placed. + */ +export interface PriorityConfiguration { + /** + * The prioritization order to use for fleet locations, when the PriorityOrder property includes LOCATION. Locations are identified by AWS Region codes such as `us-west-2. + * + * Each location can only be listed once. + */ + readonly locationOrder: string[]; + /** + * The recommended sequence to use when prioritizing where to place new game sessions. + * Each type can only be listed once. + */ + readonly priorityOrder: PriorityType[]; +} + +/** + * The queue setting that determines the highest latency allowed for individual players when placing a game session. + * When a latency policy is in force, a game session cannot be placed with any fleet in a Region where a player reports latency higher than the cap. + * + * Latency policies are only enforced when the placement request contains player latency information. + */ +export interface PlayerLatencyPolicy { + /** + * The maximum latency value that is allowed for any player, in milliseconds. + * + * All policies must have a value set for this property. + */ + readonly maximumIndividualPlayerLatency: cdk.Duration; + + /** + * The length of time, in seconds, that the policy is enforced while placing a new game session. + * + * @default the policy is enforced until the queue times out. + */ + readonly policyDuration?: cdk.Duration; +} + +/** + * Represents a Gamelift GameSessionQueue for a Gamelift fleet destination. + */ +export interface IGameSessionQueue extends cdk.IResource { + + /** + * The Name of the gameSessionQueue. + * + * @attribute + */ + readonly gameSessionQueueName: string; + + /** + * The ARN of the gameSessionQueue. + * + * @attribute + */ + readonly gameSessionQueueArn: string; + + /** + * Return the given named metric for this fleet. + */ + metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Average amount of time that game session placement requests in the queue with status PENDING have been waiting to be fulfilled. + */ + metricAverageWaitTime(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Game session placement requests that were canceled before timing out since the last report. + */ + metricPlacementsCanceled(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Game session placement requests that failed for any reason since the last report. + */ + metricPlacementsFailed(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * New game session placement requests that were added to the queue since the last report. + */ + metricPlacementsStarted(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Game session placement requests that resulted in a new game session since the last report. + */ + metricPlacementsSucceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * Game session placement requests that reached the queue's timeout limit without being fulfilled since the last report. + */ + metricPlacementsTimedOut(props?: cloudwatch.MetricOptions): cloudwatch.Metric; +} + +/** + * A full specification of an gameSessionQueue that can be used to import it fluently into the CDK application. + */ +export interface GameSessionQueueAttributes { + /** + * The ARN of the gameSessionQueue + * + * At least one of `gameSessionQueueArn` and `gameSessionQueueName` must be provided. + * + * @default derived from `gameSessionQueueName`. + */ + readonly gameSessionQueueArn?: string; + + /** + * The name of the gameSessionQueue + * + * At least one of `gameSessionQueueName` and `gameSessionQueueArn` must be provided. + * + * @default derived from `gameSessionQueueArn`. + */ + readonly gameSessionQueueName?: string; +} + +/** + * Properties for a new Fleet gameSessionQueue + */ +export interface GameSessionQueueProps { + /** + * Name of this gameSessionQueue + */ + readonly gameSessionQueueName: string; + + /** + * Information to be added to all events that are related to this game session queue. + * + * @default no customer event data + */ + readonly customEventData?: string; + + /** + * A list of locations where a queue is allowed to place new game sessions. + * + * Locations are specified in the form of AWS Region codes, such as `us-west-2`. + * + * For queues that have multi-location fleets, you can use a filter configuration allow placement with some, but not all of these locations. + * + * @default game sessions can be placed in any queue location + */ + readonly allowedLocations?: string[]; + + /** + * An SNS topic is set up to receive game session placement notifications. + * + * @default no notification + * + * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/queue-notification.html + */ + readonly notificationTarget?: sns.ITopic; + + /** + * A set of policies that act as a sliding cap on player latency. + * FleetIQ works to deliver low latency for most players in a game session. + * These policies ensure that no individual player can be placed into a game with unreasonably high latency. + * Use multiple policies to gradually relax latency requirements a step at a time. + * Multiple policies are applied based on their maximum allowed latency, starting with the lowest value. + * + * @default no player latency policy + */ + readonly playerLatencyPolicies?: PlayerLatencyPolicy[]; + + /** + * Custom settings to use when prioritizing destinations and locations for game session placements. + * This configuration replaces the FleetIQ default prioritization process. + * + * Priority types that are not explicitly named will be automatically applied at the end of the prioritization process. + * + * @default no priority configuration + */ + readonly priorityConfiguration?: PriorityConfiguration; + + /** + * The maximum time, that a new game session placement request remains in the queue. + * When a request exceeds this time, the game session placement changes to a `TIMED_OUT` status. + * + * @default 50 seconds + */ + readonly timeout?: cdk.Duration; + + /** + * A list of fleets and/or fleet alias that can be used to fulfill game session placement requests in the queue. + * + * Destinations are listed in order of placement preference. + */ + readonly destinations: IGameSessionQueueDestination[]; +} + +/** + * Base class for new and imported GameLift GameSessionQueue. + */ +export abstract class GameSessionQueueBase extends cdk.Resource implements IGameSessionQueue { + /** + * The name of the gameSessionQueue. + */ + public abstract readonly gameSessionQueueName: string; + /** + * The ARN of the gameSessionQueue + */ + public abstract readonly gameSessionQueueArn: string; + + public metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return new cloudwatch.Metric({ + namespace: 'AWS/GameLift', + metricName: metricName, + dimensionsMap: { + GameSessionQueueName: this.gameSessionQueueName, + }, + ...props, + }).attachTo(this); + } + + metricAverageWaitTime(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('AverageWaitTime', props); + } + + metricPlacementsCanceled(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('PlacementsCanceled', props); + } + + metricPlacementsFailed(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('PlacementsFailed', props); + } + + metricPlacementsStarted(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('PlacementsStarted', props); + } + + metricPlacementsSucceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('PlacementsSucceeded', props); + } + + metricPlacementsTimedOut(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return this.metric('PlacementsTimedOut', props); + } +} + +/** + * The GameSessionQueue resource creates a placement queue that processes requests for new game sessions. + * A queue uses FleetIQ algorithms to determine the best placement locations and find an available game server, then prompts the game server to start a new game session. + * Queues can have destinations (GameLift fleets or gameSessionQueuees), which determine where the queue can place new game sessions. + * A queue can have destinations with varied fleet type (Spot and On-Demand), instance type, and AWS Region. + * + * @resource AWS::GameLift::GameSessionQueue + */ +export class GameSessionQueue extends GameSessionQueueBase { + + /** + * Import an existing gameSessionQueue from its name. + */ + static fromGameSessionQueueName(scope: Construct, id: string, gameSessionQueueName: string): IGameSessionQueue { + return this.fromGameSessionQueueAttributes(scope, id, { gameSessionQueueName }); + } + + /** + * Import an existing gameSessionQueue from its ARN. + */ + static fromGameSessionQueueArn(scope: Construct, id: string, gameSessionQueueArn: string): IGameSessionQueue { + return this.fromGameSessionQueueAttributes(scope, id, { gameSessionQueueArn }); + } + + /** + * Import an existing gameSessionQueue from its attributes. + */ + static fromGameSessionQueueAttributes(scope: Construct, id: string, attrs: GameSessionQueueAttributes): IGameSessionQueue { + if (!attrs.gameSessionQueueName && !attrs.gameSessionQueueArn) { + throw new Error('Either gameSessionQueueName or gameSessionQueueArn must be provided in GameSessionQueueAttributes'); + } + const gameSessionQueueName = attrs.gameSessionQueueName ?? + cdk.Stack.of(scope).splitArn(attrs.gameSessionQueueArn!, cdk.ArnFormat.SLASH_RESOURCE_NAME).resourceName; + + if (!gameSessionQueueName) { + throw new Error(`No gameSessionQueue name found in ARN: '${attrs.gameSessionQueueArn}'`); + } + + const gameSessionQueueArn = attrs.gameSessionQueueArn ?? cdk.Stack.of(scope).formatArn({ + service: 'gamelift', + resource: 'gamesessionqueue', + resourceName: attrs.gameSessionQueueName, + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_NAME, + }); + class Import extends GameSessionQueueBase { + public readonly gameSessionQueueName = gameSessionQueueName!; + public readonly gameSessionQueueArn = gameSessionQueueArn; + + constructor(s: Construct, i: string) { + super(s, i, { + environmentFromArn: gameSessionQueueArn, + }); + } + } + return new Import(scope, id); + } + + /** + * The Identifier of the gameSessionQueue. + */ + public readonly gameSessionQueueName: string; + + /** + * The ARN of the gameSessionQueue. + */ + public readonly gameSessionQueueArn: string; + + private readonly destinations: IGameSessionQueueDestination[] = []; + + constructor(scope: Construct, id: string, props: GameSessionQueueProps) { + super(scope, id, { + physicalName: props.gameSessionQueueName, + }); + + if (!cdk.Token.isUnresolved(props.gameSessionQueueName)) { + if (props.gameSessionQueueName.length > 128) { + throw new Error(`GameSessionQueue name can not be longer than 128 characters but has ${props.gameSessionQueueName.length} characters.`); + } + + if (!/^[a-zA-Z0-9-]+$/.test(props.gameSessionQueueName)) { + throw new Error(`GameSessionQueue name ${props.gameSessionQueueName} can contain only letters, numbers, hyphens with no spaces.`); + } + } + + if (props.customEventData && props.customEventData.length > 256) { + throw new Error(`GameSessionQueue custom event data can not be longer than 256 characters but has ${props.customEventData.length} characters.`); + } + + if (props.allowedLocations && props.allowedLocations.length > 100) { + throw new Error(`No more than 100 allowed locations are allowed per game session queue, given ${props.allowedLocations.length}`); + } + + // Add all destinations + (props.destinations || []).forEach(this.addDestination.bind(this)); + + const resource = new CfnGameSessionQueue(this, 'Resource', { + name: this.physicalName, + customEventData: props.customEventData, + destinations: cdk.Lazy.any({ produce: () => this.parseDestinations() }), + filterConfiguration: this.parseFilterConfiguration(props), + notificationTarget: props.notificationTarget && props.notificationTarget.topicArn, + playerLatencyPolicies: this.parsePlayerLatencyPolicies(props), + priorityConfiguration: this.parsePriorityConfiguration(props), + timeoutInSeconds: props.timeout && props.timeout.toSeconds(), + }); + + this.gameSessionQueueName = this.getResourceNameAttribute(resource.ref); + this.gameSessionQueueArn = cdk.Stack.of(scope).formatArn({ + service: 'gamelift', + resource: 'gamesessionqueue', + resourceName: this.gameSessionQueueName, + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_NAME, + }); + } + + /** + * Adds a destination to fulfill requests for new game sessions + * + * @param destination A destination to add + */ + public addDestination(destination: IGameSessionQueueDestination) { + this.destinations.push(destination); + } + + protected parsePriorityConfiguration(props: GameSessionQueueProps): CfnGameSessionQueue.PriorityConfigurationProperty | undefined { + if (!props.priorityConfiguration) { + return undefined; + } + + if (props.priorityConfiguration.locationOrder.length > 100) { + throw new Error(`No more than 100 locations are allowed per priority configuration, given ${props.priorityConfiguration.locationOrder.length}`); + } + + if (props.priorityConfiguration.priorityOrder.length > 4) { + throw new Error(`No more than 4 priorities are allowed per priority configuration, given ${props.priorityConfiguration.priorityOrder.length}`); + } + + return { + priorityOrder: props.priorityConfiguration.priorityOrder, + locationOrder: props.priorityConfiguration.locationOrder, + }; + } + + protected parsePlayerLatencyPolicies(props: GameSessionQueueProps): CfnGameSessionQueue.PlayerLatencyPolicyProperty[] | undefined { + if (!props.playerLatencyPolicies) { + return undefined; + } + + return props.playerLatencyPolicies.map(parsePlayerLatencyPolicy); + + function parsePlayerLatencyPolicy(playerLatencyPolicy: PlayerLatencyPolicy): CfnGameSessionQueue.PlayerLatencyPolicyProperty { + return { + maximumIndividualPlayerLatencyMilliseconds: playerLatencyPolicy.maximumIndividualPlayerLatency.toMilliseconds(), + policyDurationSeconds: playerLatencyPolicy.policyDuration && playerLatencyPolicy.policyDuration.toSeconds(), + }; + } + } + + protected parseFilterConfiguration(props: GameSessionQueueProps): CfnGameSessionQueue.FilterConfigurationProperty | undefined { + if (!props.allowedLocations) { + return undefined; + } + + return { + allowedLocations: props.allowedLocations, + }; + } + + private parseDestinations(): CfnGameSessionQueue.DestinationProperty[] | undefined { + if (!this.destinations || this.destinations.length === 0) { + return undefined; + } + + return this.destinations.map(parseDestination); + + function parseDestination(destination: IGameSessionQueueDestination): CfnGameSessionQueue.DestinationProperty { + return { + destinationArn: destination.resourceArnForDestination, + }; + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/lib/index.ts b/packages/@aws-cdk/aws-gamelift/lib/index.ts index 6a74d01861c05..5f7ab5dcec93e 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/index.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/index.ts @@ -6,6 +6,7 @@ export * from './game-server-group'; export * from './ingress-rule'; export * from './fleet-base'; export * from './build-fleet'; +export * from './game-session-queue'; export * from './matchmaking-ruleset'; export * from './matchmaking-ruleset-body'; diff --git a/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture index acf0995fb04a8..3f302276c441e 100644 --- a/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture @@ -4,6 +4,7 @@ import { Duration, Size, Stack, CfnOutput } from '@aws-cdk/core'; import * as gamelift from '@aws-cdk/aws-gamelift'; import * as s3 from '@aws-cdk/aws-s3'; import * as ec2 from '@aws-cdk/aws-ec2'; +import * as sns from '@aws-cdk/aws-sns'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as path from 'path'; diff --git a/packages/@aws-cdk/aws-gamelift/test/game-session-queue.test.ts b/packages/@aws-cdk/aws-gamelift/test/game-session-queue.test.ts new file mode 100644 index 0000000000000..b030c43f95130 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/game-session-queue.test.ts @@ -0,0 +1,576 @@ + +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as gamelift from '../lib'; + +describe('gameSessionQueue', () => { + + describe('new', () => { + let stack: cdk.Stack; + let fleet: gamelift.FleetBase; + + beforeEach(() => { + stack = new cdk.Stack(); + fleet = new gamelift.BuildFleet(stack, 'MyBuildFleet', { + fleetName: 'test-fleet', + content: gamelift.Build.fromAsset(stack, 'Build', path.join(__dirname, 'my-game-build')), + instanceType: ec2.InstanceType.of(ec2.InstanceClass.C4, ec2.InstanceSize.LARGE), + runtimeConfiguration: { + serverProcesses: [{ + launchPath: 'test-launch-path', + }], + }, + }); + }); + + test('default fleet gameSessionQueue', () => { + new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + destinations: [fleet], + }); + + Template.fromStack(stack).hasResource('AWS::GameLift::GameSessionQueue', { + Properties: + { + Name: 'test-gameSessionQueue', + Destinations: [ + { + DestinationArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':gamelift:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':fleet/', + { + Ref: 'MyBuildFleet0F4EADEC', + }, + ], + ], + }, + }, + ], + }, + }); + }); + + test('default alias gameSessionQueue', () => { + const alias = new gamelift.Alias(stack, 'MyAlias', { + aliasName: 'test-alias', + fleet: fleet, + }); + + new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + destinations: [alias], + }); + + Template.fromStack(stack).hasResource('AWS::GameLift::GameSessionQueue', { + Properties: + { + Name: 'test-gameSessionQueue', + Destinations: [ + { + DestinationArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':gamelift:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':alias/', + { + Ref: 'MyAlias9A08CB8C', + }, + ], + ], + }, + }, + ], + }, + }); + }); + + test('add new destination', () => { + const alias = new gamelift.Alias(stack, 'MyAlias', { + aliasName: 'test-alias', + fleet: fleet, + }); + + const queue = new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + destinations: [fleet], + }); + + queue.addDestination(alias); + + Template.fromStack(stack).hasResource('AWS::GameLift::GameSessionQueue', { + Properties: + { + Name: 'test-gameSessionQueue', + Destinations: [ + { + DestinationArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':gamelift:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':fleet/', + { + Ref: 'MyBuildFleet0F4EADEC', + }, + ], + ], + }, + }, + { + DestinationArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':gamelift:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':alias/', + { + Ref: 'MyAlias9A08CB8C', + }, + ], + ], + }, + }, + ], + }, + }); + }); + + test('with all properties', () => { + const topic = new sns.Topic(stack, 'MyTopic', {}); + + new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + destinations: [fleet], + customEventData: 'test-event-data', + allowedLocations: ['eu-west-1', 'eu-west-2'], + notificationTarget: topic, + playerLatencyPolicies: [{ + maximumIndividualPlayerLatency: cdk.Duration.millis(100), + policyDuration: cdk.Duration.seconds(300), + }], + priorityConfiguration: { + locationOrder: [ + 'eu-west-1', + 'eu-west-2', + ], + priorityOrder: [ + gamelift.PriorityType.LATENCY, + gamelift.PriorityType.COST, + gamelift.PriorityType.DESTINATION, + gamelift.PriorityType.LOCATION, + ], + }, + timeout: cdk.Duration.seconds(300), + + }); + + Template.fromStack(stack).hasResource('AWS::GameLift::GameSessionQueue', { + Properties: + { + Name: 'test-gameSessionQueue', + CustomEventData: 'test-event-data', + FilterConfiguration: { + AllowedLocations: [ + 'eu-west-1', + 'eu-west-2', + ], + }, + NotificationTarget: { Ref: 'MyTopic86869434' }, + PlayerLatencyPolicies: [{ + MaximumIndividualPlayerLatencyMilliseconds: 100, + PolicyDurationSeconds: 300, + }], + PriorityConfiguration: { + LocationOrder: [ + 'eu-west-1', + 'eu-west-2', + ], + PriorityOrder: [ + 'LATENCY', + 'COST', + 'DESTINATION', + 'LOCATION', + ], + }, + TimeoutInSeconds: 300, + Destinations: [ + { + DestinationArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':gamelift:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':fleet/', + { + Ref: 'MyBuildFleet0F4EADEC', + }, + ], + ], + }, + }, + ], + }, + }); + }); + + test('with an invlaid priority configuration location order', () => { + let incorrectLocationOrder: string[] = []; + for (let i = 0; i < 101; i++) { + incorrectLocationOrder.push('test-location'); + } + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-name', + destinations: [fleet], + priorityConfiguration: { + locationOrder: incorrectLocationOrder, + priorityOrder: [ + gamelift.PriorityType.COST, + ], + }, + })).toThrow(/No more than 100 locations are allowed per priority configuration, given 101/); + }); + + test('with an invlaid priority configuration priority order', () => { + let incorrectPriorityOrder: gamelift.PriorityType[] = []; + for (let i = 0; i < 5; i++) { + incorrectPriorityOrder.push(gamelift.PriorityType.COST); + } + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-name', + destinations: [fleet], + priorityConfiguration: { + locationOrder: ['eu-west-1', 'eu-west-2'], + priorityOrder: incorrectPriorityOrder, + }, + })).toThrow(/No more than 4 priorities are allowed per priority configuration, given 5/); + }); + + test('with an incorrect name', () => { + let incorrectName = ''; + for (let i = 0; i < 129; i++) { + incorrectName += 'A'; + } + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: incorrectName, + destinations: [fleet], + })).toThrow(/GameSessionQueue name can not be longer than 128 characters but has 129 characters./); + }); + + test('with an incorrect name format', () => { + let incorrectName = 'test with space'; + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: incorrectName, + destinations: [fleet], + })).toThrow(/GameSessionQueue name test with space can contain only letters, numbers, hyphens with no spaces./); + }); + + test('with an incorrect custom event data', () => { + let incorrectCustomEventData = ''; + for (let i = 0; i < 257; i++) { + incorrectCustomEventData += 'A'; + } + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-name', + destinations: [fleet], + customEventData: incorrectCustomEventData, + })).toThrow(/GameSessionQueue custom event data can not be longer than 256 characters but has 257 characters./); + }); + + test('with an incorrect number of locations', () => { + let incorrectLocations: string[] = []; + for (let i = 0; i < 101; i++) { + incorrectLocations.push('test'); + } + + expect(() => new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-name', + destinations: [fleet], + allowedLocations: incorrectLocations, + })).toThrow(/No more than 100 allowed locations are allowed per game session queue, given 101/); + }); + }); + + describe('metric methods provide a Metric with configured and attached properties', () => { + let stack: cdk.Stack; + let fleet: gamelift.BuildFleet; + let gameSessionQueue: gamelift.GameSessionQueue; + + beforeEach(() => { + stack = new cdk.Stack(undefined, undefined, { env: { account: '000000000000', region: 'us-west-1' } }); + fleet = new gamelift.BuildFleet(stack, 'MyBuildFleet', { + fleetName: 'test-fleet', + content: gamelift.Build.fromAsset(stack, 'Build', path.join(__dirname, 'my-game-build')), + instanceType: ec2.InstanceType.of(ec2.InstanceClass.C4, ec2.InstanceSize.LARGE), + runtimeConfiguration: { + serverProcesses: [{ + launchPath: 'test-launch-path', + }], + }, + }); + gameSessionQueue = new gamelift.GameSessionQueue(stack, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + destinations: [fleet], + }); + }); + + test('metric', () => { + const metric = gameSessionQueue.metric('AverageWaitTime'); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'AverageWaitTime', + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricAverageWaitTime', () => { + const metric = gameSessionQueue.metricAverageWaitTime(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'AverageWaitTime', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricPlacementsCanceled', () => { + const metric = gameSessionQueue.metricPlacementsCanceled(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'PlacementsCanceled', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricPlacementsFailed', () => { + const metric = gameSessionQueue.metricPlacementsFailed(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'PlacementsFailed', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricPlacementsStarted', () => { + const metric = gameSessionQueue.metricPlacementsStarted(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'PlacementsStarted', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricPlacementsSucceeded', () => { + const metric = gameSessionQueue.metricPlacementsSucceeded(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'PlacementsSucceeded', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + test('metricPlacementsTimedOut', () => { + const metric = gameSessionQueue.metricPlacementsTimedOut(); + + expect(metric).toMatchObject({ + account: stack.account, + region: stack.region, + namespace: 'AWS/GameLift', + metricName: 'PlacementsTimedOut', + statistic: cloudwatch.Stats.AVERAGE, + dimensions: { + GameSessionQueueName: gameSessionQueue.gameSessionQueueName, + }, + }); + }); + + + }); + + describe('test import methods', () => { + test('GameSessionQueue.fromGameSessionQueueArn', () => { + // GIVEN + const stack2 = new cdk.Stack(); + + // WHEN + const imported = gamelift.GameSessionQueue.fromGameSessionQueueArn(stack2, 'Imported', 'arn:aws:gamelift:us-east-1:123456789012:gamesessionqueue/sample-gameSessionQueue-name'); + + // THEN + expect(imported.gameSessionQueueArn).toEqual('arn:aws:gamelift:us-east-1:123456789012:gamesessionqueue/sample-gameSessionQueue-name'); + expect(imported.gameSessionQueueName).toEqual('sample-gameSessionQueue-name'); + }); + + test('GameSessionQueue.fromGameSessionQueueId', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const imported = gamelift.GameSessionQueue.fromGameSessionQueueName(stack, 'Imported', 'sample-gameSessionQueue-name'); + + // THEN + expect(stack.resolve(imported.gameSessionQueueArn)).toStrictEqual({ + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':gamelift:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':gamesessionqueue/sample-gameSessionQueue-name', + ]], + }); + expect(stack.resolve(imported.gameSessionQueueName)).toStrictEqual('sample-gameSessionQueue-name'); + }); + }); + + describe('GameSessionQueue.fromGameSessionQueueAttributes()', () => { + let stack: cdk.Stack; + const gameSessionQueueName = 'gameSessionQueue-test-name'; + const gameSessionQueueArn = `arn:aws:gamelift:gameSessionQueue-region:123456789012:gamesessionqueue/${gameSessionQueueName}`; + + beforeEach(() => { + const app = new cdk.App(); + stack = new cdk.Stack(app, 'Base', { + env: { account: '111111111111', region: 'stack-region' }, + }); + }); + + describe('', () => { + test('with required attrs only', () => { + const importedFleet = gamelift.GameSessionQueue.fromGameSessionQueueAttributes(stack, 'ImportedGameSessionQueue', { gameSessionQueueArn }); + + expect(importedFleet.gameSessionQueueName).toEqual(gameSessionQueueName); + expect(importedFleet.gameSessionQueueArn).toEqual(gameSessionQueueArn); + expect(importedFleet.env.account).toEqual('123456789012'); + expect(importedFleet.env.region).toEqual('gameSessionQueue-region'); + }); + + test('with missing attrs', () => { + expect(() => gamelift.GameSessionQueue.fromGameSessionQueueAttributes(stack, 'ImportedGameSessionQueue', { })) + .toThrow(/Either gameSessionQueueName or gameSessionQueueArn must be provided in GameSessionQueueAttributes/); + }); + + test('with invalid ARN', () => { + expect(() => gamelift.GameSessionQueue.fromGameSessionQueueAttributes(stack, 'ImportedGameSessionQueue', { gameSessionQueueArn: 'arn:aws:gamelift:gameSessionQueue-region:123456789012:gamesessionqueue' })) + .toThrow(/No gameSessionQueue name found in ARN: 'arn:aws:gamelift:gameSessionQueue-region:123456789012:gamesessionqueue'/); + }); + }); + + describe('for an gameSessionQueue in a different account and region', () => { + let gameSessionQueue: gamelift.IGameSessionQueue; + + beforeEach(() => { + gameSessionQueue = gamelift.GameSessionQueue.fromGameSessionQueueAttributes(stack, 'ImportedGameSessionQueue', { gameSessionQueueArn }); + }); + + test("the gameSessionQueue's region is taken from the ARN", () => { + expect(gameSessionQueue.env.region).toBe('gameSessionQueue-region'); + }); + + test("the gameSessionQueue's account is taken from the ARN", () => { + expect(gameSessionQueue.env.account).toBe('123456789012'); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.assets.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.assets.json new file mode 100644 index 0000000000000..8395cfec6c239 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "GameSessionQueueDefaultTestDeployAssert72367A40.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-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.template.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/GameSessionQueueDefaultTestDeployAssert72367A40.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-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/TestApplicationServer b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/TestApplicationServer new file mode 100755 index 0000000000000..a4f885388c109 Binary files /dev/null and b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/TestApplicationServer differ diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/install.sh b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/install.sh new file mode 100755 index 0000000000000..1ef448e39373c --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37/install.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# make sure the gameserver is executable +/usr/bin/chmod +x /local/game/TestApplicationServer +exit 0 diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.assets.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.assets.json new file mode 100644 index 0000000000000..9c879907696ad --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.assets.json @@ -0,0 +1,32 @@ +{ + "version": "22.0.0", + "files": { + "b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37": { + "source": { + "path": "asset.b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "5cb96a6837fa171aa6c3da922798ccc4fbf1c2c083c89fe9882dfad8757930dd": { + "source": { + "path": "aws-gamelift-gameSessionQueue.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "5cb96a6837fa171aa6c3da922798ccc4fbf1c2c083c89fe9882dfad8757930dd.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-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.template.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.template.json new file mode 100644 index 0000000000000..9508d42f02f73 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/aws-gamelift-gameSessionQueue.template.json @@ -0,0 +1,280 @@ +{ + "Resources": { + "BuildServiceRole1F57E904": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "gamelift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "BuildServiceRoleDefaultPolicyCB7101C6": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject", + "s3:GetObjectVersion" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37.zip" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "BuildServiceRoleDefaultPolicyCB7101C6", + "Roles": [ + { + "Ref": "BuildServiceRole1F57E904" + } + ] + } + }, + "Build45A36621": { + "Type": "AWS::GameLift::Build", + "Properties": { + "OperatingSystem": "AMAZON_LINUX_2", + "StorageLocation": { + "Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "Key": "b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37.zip", + "RoleArn": { + "Fn::GetAtt": [ + "BuildServiceRole1F57E904", + "Arn" + ] + } + } + }, + "DependsOn": [ + "BuildServiceRoleDefaultPolicyCB7101C6", + "BuildServiceRole1F57E904" + ] + }, + "BuildFleetServiceRole32D49FB4": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ec2.amazonaws.com", + "gamelift.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "BuildFleet027ED403": { + "Type": "AWS::GameLift::Fleet", + "Properties": { + "BuildId": { + "Ref": "Build45A36621" + }, + "CertificateConfiguration": { + "CertificateType": "DISABLED" + }, + "EC2InboundPermissions": [ + { + "FromPort": 1935, + "IpRange": "0.0.0.0/0", + "Protocol": "TCP", + "ToPort": 1935 + } + ], + "EC2InstanceType": "c5.large", + "FleetType": "ON_DEMAND", + "InstanceRoleARN": { + "Fn::GetAtt": [ + "BuildFleetServiceRole32D49FB4", + "Arn" + ] + }, + "MaxSize": 1, + "MinSize": 0, + "Name": "test-fleet", + "NewGameSessionProtectionPolicy": "NoProtection", + "RuntimeConfiguration": { + "GameSessionActivationTimeoutSeconds": 300, + "MaxConcurrentGameSessionActivations": 1, + "ServerProcesses": [ + { + "ConcurrentExecutions": 1, + "LaunchPath": "/local/game/TestApplicationServer", + "Parameters": "port:1935 gameSessionLengthSeconds:20" + } + ] + } + } + }, + "BuildFleetAliaslive3FE0BB2F": { + "Type": "AWS::GameLift::Alias", + "Properties": { + "Name": "live", + "RoutingStrategy": { + "FleetId": { + "Ref": "BuildFleet027ED403" + }, + "Type": "SIMPLE" + } + } + }, + "MyTopic86869434": { + "Type": "AWS::SNS::Topic" + }, + "MyGameSessionQueue1A15CE31": { + "Type": "AWS::GameLift::GameSessionQueue", + "Properties": { + "Name": "test-gameSessionQueue", + "CustomEventData": "test-event-data", + "Destinations": [ + { + "DestinationArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":gamelift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":fleet/", + { + "Ref": "BuildFleet027ED403" + } + ] + ] + } + }, + { + "DestinationArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":gamelift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":alias/", + { + "Ref": "BuildFleetAliaslive3FE0BB2F" + } + ] + ] + } + } + ], + "FilterConfiguration": { + "AllowedLocations": [ + "eu-west-1", + "eu-west-2" + ] + }, + "NotificationTarget": { + "Ref": "MyTopic86869434" + }, + "PlayerLatencyPolicies": [ + { + "MaximumIndividualPlayerLatencyMilliseconds": 100, + "PolicyDurationSeconds": 300 + } + ], + "PriorityConfiguration": { + "LocationOrder": [ + "eu-west-1", + "eu-west-2" + ], + "PriorityOrder": [ + "LATENCY", + "COST", + "DESTINATION", + "LOCATION" + ] + }, + "TimeoutInSeconds": 300 + } + } + }, + "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-gamelift/test/integ.game-session-queue.js.snapshot/cdk.out b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/cdk.out new file mode 100644 index 0000000000000..145739f539580 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/integ.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/integ.json new file mode 100644 index 0000000000000..ae846e648bf63 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "22.0.0", + "testCases": { + "GameSessionQueue/DefaultTest": { + "stacks": [ + "aws-gamelift-gameSessionQueue" + ], + "assertionStack": "GameSessionQueue/DefaultTest/DeployAssert", + "assertionStackName": "GameSessionQueueDefaultTestDeployAssert72367A40" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/manifest.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/manifest.json new file mode 100644 index 0000000000000..ffee6d0974a64 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/manifest.json @@ -0,0 +1,153 @@ +{ + "version": "22.0.0", + "artifacts": { + "aws-gamelift-gameSessionQueue.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-gamelift-gameSessionQueue.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-gamelift-gameSessionQueue": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-gamelift-gameSessionQueue.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}/5cb96a6837fa171aa6c3da922798ccc4fbf1c2c083c89fe9882dfad8757930dd.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-gamelift-gameSessionQueue.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": [ + "aws-gamelift-gameSessionQueue.assets" + ], + "metadata": { + "/aws-gamelift-gameSessionQueue/Build/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildServiceRole1F57E904" + } + ], + "/aws-gamelift-gameSessionQueue/Build/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildServiceRoleDefaultPolicyCB7101C6" + } + ], + "/aws-gamelift-gameSessionQueue/Build/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Build45A36621" + } + ], + "/aws-gamelift-gameSessionQueue/BuildFleet/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildFleetServiceRole32D49FB4" + } + ], + "/aws-gamelift-gameSessionQueue/BuildFleet/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildFleet027ED403" + } + ], + "/aws-gamelift-gameSessionQueue/BuildFleet/Aliaslive/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildFleetAliaslive3FE0BB2F" + } + ], + "/aws-gamelift-gameSessionQueue/MyTopic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTopic86869434" + } + ], + "/aws-gamelift-gameSessionQueue/MyGameSessionQueue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyGameSessionQueue1A15CE31" + } + ], + "/aws-gamelift-gameSessionQueue/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-gamelift-gameSessionQueue/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-gamelift-gameSessionQueue" + }, + "GameSessionQueueDefaultTestDeployAssert72367A40.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "GameSessionQueueDefaultTestDeployAssert72367A40.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "GameSessionQueueDefaultTestDeployAssert72367A40": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "GameSessionQueueDefaultTestDeployAssert72367A40.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": [ + "GameSessionQueueDefaultTestDeployAssert72367A40.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": [ + "GameSessionQueueDefaultTestDeployAssert72367A40.assets" + ], + "metadata": { + "/GameSessionQueue/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/GameSessionQueue/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "GameSessionQueue/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/tree.json b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/tree.json new file mode 100644 index 0000000000000..98d8118a06156 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.js.snapshot/tree.json @@ -0,0 +1,534 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-gamelift-gameSessionQueue": { + "id": "aws-gamelift-gameSessionQueue", + "path": "aws-gamelift-gameSessionQueue", + "children": { + "Build": { + "id": "Build", + "path": "aws-gamelift-gameSessionQueue/Build", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-gamelift-gameSessionQueue/Build/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-gamelift-gameSessionQueue/Build/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/Build/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "gamelift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-gamelift-gameSessionQueue/Build/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/Build/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject", + "s3:GetObjectVersion" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37.zip" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "BuildServiceRoleDefaultPolicyCB7101C6", + "roles": [ + { + "Ref": "BuildServiceRole1F57E904" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Content": { + "id": "Content", + "path": "aws-gamelift-gameSessionQueue/Build/Content", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-gamelift-gameSessionQueue/Build/Content/Stage", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-gamelift-gameSessionQueue/Build/Content/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-gamelift-gameSessionQueue/Build/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/Build/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::GameLift::Build", + "aws:cdk:cloudformation:props": { + "operatingSystem": "AMAZON_LINUX_2", + "storageLocation": { + "bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "key": "b95e4173bc399a8f686a4951aa26e01de1ed1e9d981ee1a7f18a15512dbdcb37.zip", + "roleArn": { + "Fn::GetAtt": [ + "BuildServiceRole1F57E904", + "Arn" + ] + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.CfnBuild", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.Build", + "version": "0.0.0" + } + }, + "BuildFleet": { + "id": "BuildFleet", + "path": "aws-gamelift-gameSessionQueue/BuildFleet", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ec2.amazonaws.com", + "gamelift.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::GameLift::Fleet", + "aws:cdk:cloudformation:props": { + "buildId": { + "Ref": "Build45A36621" + }, + "certificateConfiguration": { + "certificateType": "DISABLED" + }, + "ec2InboundPermissions": [ + { + "protocol": "TCP", + "fromPort": 1935, + "toPort": 1935, + "ipRange": "0.0.0.0/0" + } + ], + "ec2InstanceType": "c5.large", + "fleetType": "ON_DEMAND", + "instanceRoleArn": { + "Fn::GetAtt": [ + "BuildFleetServiceRole32D49FB4", + "Arn" + ] + }, + "maxSize": 1, + "minSize": 0, + "name": "test-fleet", + "newGameSessionProtectionPolicy": "NoProtection", + "runtimeConfiguration": { + "gameSessionActivationTimeoutSeconds": 300, + "maxConcurrentGameSessionActivations": 1, + "serverProcesses": [ + { + "parameters": "port:1935 gameSessionLengthSeconds:20", + "launchPath": "/local/game/TestApplicationServer", + "concurrentExecutions": 1 + } + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.CfnFleet", + "version": "0.0.0" + } + }, + "Aliaslive": { + "id": "Aliaslive", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/Aliaslive", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/BuildFleet/Aliaslive/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::GameLift::Alias", + "aws:cdk:cloudformation:props": { + "name": "live", + "routingStrategy": { + "fleetId": { + "Ref": "BuildFleet027ED403" + }, + "type": "SIMPLE" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.CfnAlias", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.Alias", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.BuildFleet", + "version": "0.0.0" + } + }, + "MyTopic": { + "id": "MyTopic", + "path": "aws-gamelift-gameSessionQueue/MyTopic", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/MyTopic/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SNS::Topic", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sns.CfnTopic", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sns.Topic", + "version": "0.0.0" + } + }, + "MyGameSessionQueue": { + "id": "MyGameSessionQueue", + "path": "aws-gamelift-gameSessionQueue/MyGameSessionQueue", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-gamelift-gameSessionQueue/MyGameSessionQueue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::GameLift::GameSessionQueue", + "aws:cdk:cloudformation:props": { + "name": "test-gameSessionQueue", + "customEventData": "test-event-data", + "destinations": [ + { + "destinationArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":gamelift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":fleet/", + { + "Ref": "BuildFleet027ED403" + } + ] + ] + } + }, + { + "destinationArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":gamelift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":alias/", + { + "Ref": "BuildFleetAliaslive3FE0BB2F" + } + ] + ] + } + } + ], + "filterConfiguration": { + "allowedLocations": [ + "eu-west-1", + "eu-west-2" + ] + }, + "notificationTarget": { + "Ref": "MyTopic86869434" + }, + "playerLatencyPolicies": [ + { + "maximumIndividualPlayerLatencyMilliseconds": 100, + "policyDurationSeconds": 300 + } + ], + "priorityConfiguration": { + "priorityOrder": [ + "LATENCY", + "COST", + "DESTINATION", + "LOCATION" + ], + "locationOrder": [ + "eu-west-1", + "eu-west-2" + ] + }, + "timeoutInSeconds": 300 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.CfnGameSessionQueue", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.GameSessionQueue", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-gamelift-gameSessionQueue/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-gamelift-gameSessionQueue/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "GameSessionQueue": { + "id": "GameSessionQueue", + "path": "GameSessionQueue", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "GameSessionQueue/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "GameSessionQueue/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "GameSessionQueue/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "GameSessionQueue/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "GameSessionQueue/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + } + }, + "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.168" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.ts b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.ts new file mode 100644 index 0000000000000..9e1a6793fb63a --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.game-session-queue.ts @@ -0,0 +1,77 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import { Duration } from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import { Construct } from 'constructs'; +import * as gamelift from '../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const build = new gamelift.Build(this, 'Build', { + content: gamelift.Content.fromAsset(path.join(__dirname, 'my-game-build')), + operatingSystem: gamelift.OperatingSystem.AMAZON_LINUX_2, + }); + + const fleet = new gamelift.BuildFleet(this, 'BuildFleet', { + fleetName: 'test-fleet', + content: build, + ingressRules: [{ + source: gamelift.Peer.anyIpv4(), + port: gamelift.Port.tcp(1935), + }], + instanceType: ec2.InstanceType.of(ec2.InstanceClass.C5, ec2.InstanceSize.LARGE), + runtimeConfiguration: { + gameSessionActivationTimeout: Duration.seconds(300), + maxConcurrentGameSessionActivations: 1, + serverProcesses: [{ + launchPath: '/local/game/TestApplicationServer', + parameters: 'port:1935 gameSessionLengthSeconds:20', + concurrentExecutions: 1, + }], + }, + }); + const alias = fleet.addAlias('live'); + + const topic = new sns.Topic(this, 'MyTopic', {}); + + const queue = new gamelift.GameSessionQueue(this, 'MyGameSessionQueue', { + gameSessionQueueName: 'test-gameSessionQueue', + customEventData: 'test-event-data', + allowedLocations: ['eu-west-1', 'eu-west-2'], + destinations: [fleet], + notificationTarget: topic, + playerLatencyPolicies: [{ + maximumIndividualPlayerLatency: cdk.Duration.millis(100), + policyDuration: cdk.Duration.seconds(300), + }], + priorityConfiguration: { + locationOrder: [ + 'eu-west-1', + 'eu-west-2', + ], + priorityOrder: [ + gamelift.PriorityType.LATENCY, + gamelift.PriorityType.COST, + gamelift.PriorityType.DESTINATION, + gamelift.PriorityType.LOCATION, + ], + }, + timeout: cdk.Duration.seconds(300), + }); + + queue.addDestination(alias); + } +} + +// Beginning of the test suite +const app = new cdk.App(); +const stack = new TestStack(app, 'aws-gamelift-gameSessionQueue'); +new IntegTest(app, 'GameSessionQueue', { + testCases: [stack], +}); + +app.synth(); \ No newline at end of file