Skip to content

Commit

Permalink
Merge branch 'master' into csumpter/fix-cross-region-authorizer-ref
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jan 21, 2022
2 parents 40f23e2 + 0e78aeb commit b44025c
Show file tree
Hide file tree
Showing 21 changed files with 437 additions and 54 deletions.
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assertions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ expect(result.Foo).toEqual({ Value: 'Fred', Description: 'FooFred' });
expect(result.Bar).toEqual({ Value: 'Fred', Description: 'BarFred' });
```

The APIs `hasMapping()` and `findMappings()` provide similar functionalities.
The APIs `hasMapping()`, `findMappings()`, `hasCondition()`, and `hasCondtions()` provide similar functionalities.

## Special Matchers

Expand Down
30 changes: 30 additions & 0 deletions packages/@aws-cdk/assertions/lib/private/conditions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { filterLogicalId, formatFailure, matchSection } from './section';
import { Template } from './template';

export function findConditions(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } {
const section: { [key: string] : {} } = template.Conditions;
const result = matchSection(filterLogicalId(section, logicalId), props);

if (!result.match) {
return {};
}

return result.matches;
}

export function hasCondition(template: Template, logicalId: string, props: any): string | void {
const section: { [key: string] : {} } = template.Conditions;
const result = matchSection(filterLogicalId(section, logicalId), props);
if (result.match) {
return;
}

if (result.closestResult === undefined) {
return 'No conditions found in the template';
}

return [
`Template has ${result.analyzedCount} conditions, but none match as expected.`,
formatFailure(result.closestResult),
].join('\n');
}
7 changes: 5 additions & 2 deletions packages/@aws-cdk/assertions/lib/private/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export type Template = {
Resources: { [logicalId: string]: Resource },
Outputs: { [logicalId: string]: Output },
Mappings: { [logicalId: string]: Mapping },
Parameters: { [logicalId: string]: Parameter }
Parameters: { [logicalId: string]: Parameter },
Conditions: { [logicalId: string]: Condition },
}

export type Resource = {
Expand All @@ -19,4 +20,6 @@ export type Mapping = { [key: string]: any };
export type Parameter = {
Type: string;
[key: string]: any;
}
}

export type Condition = { [key: string]: any };
26 changes: 26 additions & 0 deletions packages/@aws-cdk/assertions/lib/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Stack, Stage } from '@aws-cdk/core';
import * as fs from 'fs-extra';
import { Match } from './match';
import { Matcher } from './matcher';
import { findConditions, hasCondition } from './private/conditions';
import { findMappings, hasMapping } from './private/mappings';
import { findOutputs, hasOutput } from './private/outputs';
import { findParameters, hasParameter } from './private/parameters';
Expand Down Expand Up @@ -183,6 +184,31 @@ export class Template {
return findMappings(this.template, logicalId, props);
}

/**
* Assert that a Condition with the given properties exists in the CloudFormation template.
* By default, performs partial matching on the resource, via the `Match.objectLike()`.
* To configure different behavour, use other matchers in the `Match` class.
* @param logicalId the name of the mapping. Provide `'*'` to match all conditions in the template.
* @param props the output as should be expected in the template.
*/
public hasCondition(logicalId: string, props: any): void {
const matchError = hasCondition(this.template, logicalId, props);
if (matchError) {
throw new Error(matchError);
}
}

/**
* Get the set of matching Conditions that match the given properties in the CloudFormation template.
* @param logicalId the name of the condition. Provide `'*'` to match all conditions in the template.
* @param props by default, matches all Conditions in the template.
* When a literal object is provided, performs a partial match via `Match.objectLike()`.
* Use the `Match` APIs to configure a different behaviour.
*/
public findConditions(logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } {
return findConditions(this.template, logicalId, props);
}

/**
* Assert that the CloudFormation template matches the given value
* @param expected the expected CloudFormation template as key-value pairs.
Expand Down
146 changes: 145 additions & 1 deletion packages/@aws-cdk/assertions/test/template.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { App, CfnMapping, CfnOutput, CfnParameter, CfnResource, NestedStack, Stack } from '@aws-cdk/core';
import { App, CfnCondition, CfnMapping, CfnOutput, CfnParameter, CfnResource, Fn, NestedStack, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { Capture, Match, Template } from '../lib';

Expand Down Expand Up @@ -940,6 +940,150 @@ describe('Template', () => {
expect(Object.keys(result).length).toEqual(0);
});
});

describe('hasCondition', () => {
test('matching', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

const inspect = Template.fromStack(stack);
expect(() => inspect.hasCondition('*', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow();
});

test('not matching', (done) => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

new CfnCondition(stack, 'Qux', {
expression: Fn.conditionNot(Fn.conditionEquals('Quux', 'Quuz')),
});

const inspect = Template.fromStack(stack);
expectToThrow(
() => inspect.hasCondition('*', {
'Fn::Equals': ['Baz', 'Bar'],
}),
[
/2 conditions/,
/Missing key/,
],
done,
);
done();
});

test('matching specific outputName', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

const inspect = Template.fromStack(stack);
expect(() => inspect.hasCondition('Foo', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow();
});

test('not matching specific outputName', (done) => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Baz', 'Bar'),
});

const inspect = Template.fromStack(stack);
expectToThrow(
() => inspect.hasCondition('Foo', {
'Fn::Equals': ['Bar', 'Baz'],
}),
[
/1 conditions/,
/Expected Baz but received Bar/,
],
done,
);
done();
});
});

describe('findConditions', () => {
test('matching', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

new CfnCondition(stack, 'Qux', {
expression: Fn.conditionNot(Fn.conditionEquals('Quux', 'Quuz')),
});

const inspect = Template.fromStack(stack);
const firstCondition = inspect.findConditions('Foo');
expect(firstCondition).toEqual({
Foo: {
'Fn::Equals': [
'Bar',
'Baz',
],
},
});

const secondCondition = inspect.findConditions('Qux');
expect(secondCondition).toEqual({
Qux: {
'Fn::Not': [
{
'Fn::Equals': [
'Quux',
'Quuz',
],
},
],
},
});
});

test('not matching', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

const inspect = Template.fromStack(stack);
const result = inspect.findMappings('Bar');
expect(Object.keys(result).length).toEqual(0);
});

test('matching with specific outputName', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

const inspect = Template.fromStack(stack);
const result = inspect.findConditions('Foo', { 'Fn::Equals': ['Bar', 'Baz'] });
expect(result).toEqual({
Foo: {
'Fn::Equals': [
'Bar',
'Baz',
],
},
});
});

test('not matching specific output name', () => {
const stack = new Stack();
new CfnCondition(stack, 'Foo', {
expression: Fn.conditionEquals('Bar', 'Baz'),
});

const inspect = Template.fromStack(stack);
const result = inspect.findConditions('Foo', { 'Fn::Equals': ['Bar', 'Qux'] });
expect(Object.keys(result).length).toEqual(0);
});
});
});

function expectToThrow(fn: () => void, msgs: (RegExp | string)[], done: jest.DoneCallback): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export abstract class NetworkLoadBalancedServiceBase extends CoreConstruct {
const loadBalancer = props.loadBalancer ?? new NetworkLoadBalancer(this, 'LB', lbProps);
const listenerPort = props.listenerPort ?? 80;
const targetProps = {
port: 80,
port: props.taskImageOptions?.containerPort ?? 80,
};

this.listener = loadBalancer.addListener('PublicListener', { port: listenerPort });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends CoreConstru
protected registerECSTargets(service: BaseService, container: ContainerDefinition, targets: NetworkTargetProps[]): NetworkTargetGroup {
for (const targetProps of targets) {
const targetGroup = this.findListener(targetProps.listener).addTargets(`ECSTargetGroup${container.containerName}${targetProps.containerPort}`, {
port: 80,
port: targetProps.containerPort ?? 80,
targets: [
service.loadBalancerTarget({
containerName: container.containerName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"myServicelb2listener2ECSTargetGroupweb90Group6841F924": {
"Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
"Properties": {
"Port": 80,
"Port": 90,
"Protocol": "TCP",
"TargetType": "ip",
"VpcId": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@
"FargateNlbServiceLBPublicListenerECSGroup7501571D": {
"Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
"Properties": {
"Port": 80,
"Port": 2015,
"Protocol": "TCP",
"TargetType": "ip",
"VpcId": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Match, Template } from '@aws-cdk/assertions';
import { Vpc } from '@aws-cdk/aws-ec2';
import * as ecs from '@aws-cdk/aws-ecs';
import { ContainerImage } from '@aws-cdk/aws-ecs';
import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import { Duration, Stack } from '@aws-cdk/core';
import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib';
import { ApplicationLoadBalancedFargateService, ApplicationMultipleTargetGroupsFargateService, NetworkLoadBalancedFargateService, NetworkMultipleTargetGroupsFargateService } from '../../lib';

describe('When Application Load Balancer', () => {
test('test Fargate loadbalanced construct with default settings', () => {
Expand Down Expand Up @@ -661,4 +662,75 @@ describe('When Network Load Balancer', () => {
});
}).toThrow(/You must specify one of: taskDefinition or image/);
});

test('test Fargate networkloadbalanced construct with custom Port', () => {
// GIVEN
const stack = new Stack();
const vpc = new Vpc(stack, 'VPC');
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });

new NetworkLoadBalancedFargateService(stack, 'NLBService', {
cluster: cluster,
memoryLimitMiB: 1024,
cpu: 512,
taskImageOptions: {
image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
containerPort: 81,
},
listenerPort: 8181,
});

Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', {
Port: 81,
Protocol: 'TCP',
TargetType: 'ip',
VpcId: {
Ref: 'VPCB9E5F0B4',
},
});
});

test('test Fargate multinetworkloadbalanced construct with custom Port', () => {
// GIVEN
const stack = new Stack();
const vpc = new Vpc(stack, 'VPC');
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });

new NetworkMultipleTargetGroupsFargateService(stack, 'Service', {
cluster,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('test'),
},
});


new NetworkMultipleTargetGroupsFargateService(stack, 'NLBService', {
cluster: cluster,
memoryLimitMiB: 1024,
cpu: 512,
taskImageOptions: {
image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
},
loadBalancers: [
{
name: 'lb1',
listeners: [
{ name: 'listener1', port: 8181 },
],
},
],
targetGroups: [{
containerPort: 81,
}],
});

Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::TargetGroup', {
Port: 81,
Protocol: 'TCP',
TargetType: 'ip',
VpcId: {
Ref: 'VPCB9E5F0B4',
},
});
});
});
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ new lambda.NodejsFunction(this, 'my-handler', {
footer: '/* comments */', // requires esbuild >= 0.9.0, defaults to none
charset: lambda.Charset.UTF8, // do not escape non-ASCII characters, defaults to Charset.ASCII
format: lambda.OutputFormat.ESM, // ECMAScript module output format, defaults to OutputFormat.CJS (OutputFormat.ESM requires Node.js 14.x)
mainFields: ['module', 'main'], // prefer ECMAScript versions of dependencies
},
});
```
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export class Bundling implements cdk.BundlingOptions {
...this.props.banner ? [`--banner:js=${JSON.stringify(this.props.banner)}`] : [],
...this.props.footer ? [`--footer:js=${JSON.stringify(this.props.footer)}`] : [],
...this.props.charset ? [`--charset=${this.props.charset}`] : [],
...this.props.mainFields ? [`--main-fields=${this.props.mainFields.join(',')}`] : [],
];

let depsCommand = '';
Expand Down
Loading

0 comments on commit b44025c

Please sign in to comment.