Skip to content

Commit

Permalink
Adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rix0rrr committed Apr 27, 2019
1 parent b3cd0bc commit 7766d0e
Show file tree
Hide file tree
Showing 19 changed files with 2,058 additions and 149 deletions.
62 changes: 39 additions & 23 deletions packages/@aws-cdk/assert/jest.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,55 @@
import { Stack } from "@aws-cdk/cdk";
import { SynthesizedStack } from "@aws-cdk/cx-api";
import { haveResource, ResourcePart } from "./lib/assertions/have-resource";
import { HaveResourceAssertion, ResourcePart } from "./lib/assertions/have-resource";
import { expect as ourExpect } from './lib/expect';

declare global {
namespace jest {
interface Matchers<R> {
toHaveResource(resourceType: string,
properties?: any,
comparison?: ResourcePart,
allowValueExtension?: boolean): R;
comparison?: ResourcePart): R;

toHaveResourceLike(resourceType: string,
properties?: any,
comparison?: ResourcePart): R;
}
}
}

expect.extend({
toHaveResource(actual: SynthesizedStack | Stack,
resourceType: string,
properties?: any,
comparison?: ResourcePart,
allowValueExtension: boolean = false) {
toHaveResource(
actual: SynthesizedStack | Stack,
resourceType: string,
properties?: any,
comparison?: ResourcePart) {

const assertion = haveResource(resourceType, properties, comparison, allowValueExtension);
const inspector = ourExpect(actual);
const pass = assertion.assertUsing(inspector);
if (pass) {
return {
pass,
message: `Expected ${JSON.stringify(inspector.value, null, 2)} not to match ${assertion.description}`,
};
} else {
return {
pass,
message: `Expected ${JSON.stringify(inspector.value, null, 2)} to match ${assertion.description}`,
};
}
const assertion = new HaveResourceAssertion(resourceType, properties, comparison, false);
return assertHaveResource(assertion, actual);
},
toHaveResourceLike(
actual: SynthesizedStack | Stack,
resourceType: string,
properties?: any,
comparison?: ResourcePart) {

const assertion = new HaveResourceAssertion(resourceType, properties, comparison, true);
return assertHaveResource(assertion, actual);
}
});

function assertHaveResource(assertion: HaveResourceAssertion, actual: SynthesizedStack | Stack) {
const inspector = ourExpect(actual);
const pass = assertion.assertUsing(inspector);
if (pass) {
return {
pass,
message: () => `Not ` + assertion.generateErrorMessage(),
};
} else {
return {
pass,
message: () => assertion.generateErrorMessage(),
};
}
});
}
24 changes: 14 additions & 10 deletions packages/@aws-cdk/assert/lib/assertions/have-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function haveResourceLike(resourceType: string,

type PropertyPredicate = (props: any, inspection: InspectionFailure) => boolean;

class HaveResourceAssertion extends Assertion<StackInspector> {
export class HaveResourceAssertion extends Assertion<StackInspector> {
private inspected: InspectionFailure[] = [];
private readonly part: ResourcePart;
private readonly predicate: PropertyPredicate;
Expand Down Expand Up @@ -66,17 +66,21 @@ class HaveResourceAssertion extends Assertion<StackInspector> {
return false;
}

public assertOrThrow(inspector: StackInspector) {
if (!this.assertUsing(inspector)) {
const lines: string[] = [];
lines.push(`None of ${this.inspected.length} resources matches ${this.description}.`);
public generateErrorMessage() {
const lines: string[] = [];
lines.push(`None of ${this.inspected.length} resources matches ${this.description}.`);

for (const inspected of this.inspected) {
lines.push(`- ${inspected.failureReason} in:`);
lines.push(indent(4, JSON.stringify(inspected.resource, null, 2)));
}
for (const inspected of this.inspected) {
lines.push(`- ${inspected.failureReason} in:`);
lines.push(indent(4, JSON.stringify(inspected.resource, null, 2)));
}

throw new Error(lines.join('\n'));
return lines.join('\n');
}

public assertOrThrow(inspector: StackInspector) {
if (!this.assertUsing(inspector)) {
throw new Error(this.generateErrorMessage());
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-stepfunctions-tasks/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ dist
!.jsii

*.snk
tsconfig.*
*.tsbuildinfo
107 changes: 60 additions & 47 deletions packages/@aws-cdk/aws-stepfunctions-tasks/lib/base-run-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,41 @@ import cdk = require('@aws-cdk/cdk');
/**
* Properties for SendMessageTask
*/
export interface BaseRunTaskProps extends stepfunctions.BasicTaskProps {
export interface CommonRunTaskProps extends stepfunctions.BasicTaskProps {
/**
* The topic to run the task on
*/
cluster: ecs.ICluster;
readonly cluster: ecs.ICluster;

/**
* Task Definition used for running tasks in the service
*/
taskDefinition: ecs.TaskDefinition;
readonly taskDefinition: ecs.TaskDefinition;

/**
* Container setting overrides
*
* Key is the name of the container to override, value is the
* values you want to override.
*/
containerOverrides?: ContainerOverride[];
readonly containerOverrides?: ContainerOverride[];

/**
* Whether to wait for the task to complete and return the response
*
* @default true
*/
synchronous?: boolean;
readonly synchronous?: boolean;
}

/**
* Construction properties for the BaseRunTaskProps
*/
export interface BaseRunTaskProps extends CommonRunTaskProps {
/**
* Additional parameters to pass to the base task
*/
readonly parameters?: {[key: string]: any};
}

export interface ContainerOverride {
Expand All @@ -40,75 +50,75 @@ export interface ContainerOverride {
*
* Exactly one of `containerName` and `containerNamePath` is required.
*/
containerName?: string;
readonly containerName?: string;

/**
* JSONPath expression for the name of the container inside the task definition
*
* Exactly one of `containerName` and `containerNamePath` is required.
*/
containerNamePath?: string;
readonly containerNamePath?: string;

/**
* Command to run inside the container
*
* @default Default command
*/
command?: string[];
readonly command?: string[];

/**
* JSON expression for command to run inside the container
*
* @default Default command
*/
commandPath?: string;
readonly commandPath?: string;

/**
* Variables to set in the container's environment
*/
environment?: TaskEnvironmentVariable[];
readonly environment?: TaskEnvironmentVariable[];

/**
* The number of cpu units reserved for the container
*
* @Default The default value from the task definition.
*/
cpu?: number;
readonly cpu?: number;

/**
* JSON expression for the number of CPU units
*
* @Default The default value from the task definition.
*/
cpuPath?: string;
readonly cpuPath?: string;

/**
* Hard memory limit on the container
*
* @Default The default value from the task definition.
*/
memoryLimit?: number;
readonly memoryLimit?: number;

/**
* JSON expression path for the hard memory limit
*
* @Default The default value from the task definition.
*/
memoryLimitPath?: string;
readonly memoryLimitPath?: string;

/**
* Soft memory limit on the container
*
* @Default The default value from the task definition.
*/
memoryReservation?: number;
readonly memoryReservation?: number;

/**
* JSONExpr path for memory limit on the container
*
* @Default The default value from the task definition.
*/
memoryReservationPath?: number;
readonly memoryReservationPath?: number;
}

/**
Expand All @@ -120,28 +130,28 @@ export interface TaskEnvironmentVariable {
*
* Exactly one of `name` and `namePath` must be specified.
*/
name?: string;
readonly name?: string;

/**
* JSONExpr for the name of the variable
*
* Exactly one of `name` and `namePath` must be specified.
*/
namePath?: string;
readonly namePath?: string;

/**
* Value of the environment variable
*
* Exactly one of `value` and `valuePath` must be specified.
*/
value?: string;
readonly value?: string;

/**
* JSONPath expr for the environment variable
*
* Exactly one of `value` and `valuePath` must be specified.
*/
valuePath?: string;
readonly valuePath?: string;
}

/**
Expand All @@ -154,34 +164,33 @@ export class BaseRunTask extends stepfunctions.Task implements ec2.IConnectable
public readonly connections: ec2.Connections = new ec2.Connections();

protected networkConfiguration?: any;
protected readonly _parameters: {[key: string]: any} = {};
protected readonly taskDefinition: ecs.TaskDefinition;
private readonly sync: boolean;

constructor(scope: cdk.Construct, id: string, props: BaseRunTaskProps) {
super(scope, id, {
...props,
resourceArn: 'arn:aws:states:::ecs:runTask' + (props.synchronous !== false ? '.sync' : ''),
parameters: new cdk.Token(() => ({
parameters: {
Cluster: props.cluster.clusterArn,
TaskDefinition: props.taskDefinition.taskDefinitionArn,
NetworkConfiguration: this.networkConfiguration,
...this._parameters
}))
NetworkConfiguration: new cdk.Token(() => this.networkConfiguration),
Overrides: renderOverrides(props.containerOverrides),
...props.parameters,
}
});

this.sync = props.synchronous !== false;
this._parameters.Overrides = this.renderOverrides(props.containerOverrides);
this.taskDefinition = props.taskDefinition;
}

protected configureAwsVpcNetworking(
vpc: ec2.IVpcNetwork,
assignPublicIp?: boolean,
subnetSelection?: ec2.VpcSubnetSelection,
subnetSelection?: ec2.SubnetSelection,
securityGroup?: ec2.ISecurityGroup) {
if (subnetSelection === undefined) {
subnetSelection = { subnetsToUse: assignPublicIp ? ec2.SubnetType.Public : ec2.SubnetType.Private };
subnetSelection = { subnetType: assignPublicIp ? ec2.SubnetType.Public : ec2.SubnetType.Private };
}
if (securityGroup === undefined) {
securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc });
Expand Down Expand Up @@ -225,27 +234,10 @@ export class BaseRunTask extends stepfunctions.Task implements ec2.IConnectable
resourceName: 'StepFunctionsGetEventsForECSTaskRule'
})));
}
}

private renderOverrides(containerOverrides?: ContainerOverride[]) {
if (!containerOverrides) { return undefined; }

const ret = new Array<any>();
for (const override of containerOverrides) {
ret.push({
...extractRequired(override, 'containerName', 'Name'),
...extractOptional(override, 'command', 'Command'),
...extractOptional(override, 'cpu', 'Cpu'),
...extractOptional(override, 'memoryLimit', 'Memory'),
...extractOptional(override, 'memoryReservation', 'MemoryReservation'),
Environment: override.environment && override.environment.map(e => ({
...extractRequired(e, 'name', 'Name'),
...extractRequired(e, 'value', 'Value'),
}))
});
for (const policyStatement of policyStatements) {
graph.registerPolicyStatement(policyStatement);
}

return { ContainerOverrides: ret };
}

private taskExecutionRoles(): iam.IRole[] {
Expand All @@ -266,6 +258,27 @@ function extractRequired(obj: any, srcKey: string, dstKey: string) {
return mapValue(obj, srcKey, dstKey);
}

function renderOverrides(containerOverrides?: ContainerOverride[]) {
if (!containerOverrides) { return undefined; }

const ret = new Array<any>();
for (const override of containerOverrides) {
ret.push({
...extractRequired(override, 'containerName', 'Name'),
...extractOptional(override, 'command', 'Command'),
...extractOptional(override, 'cpu', 'Cpu'),
...extractOptional(override, 'memoryLimit', 'Memory'),
...extractOptional(override, 'memoryReservation', 'MemoryReservation'),
Environment: override.environment && override.environment.map(e => ({
...extractRequired(e, 'name', 'Name'),
...extractRequired(e, 'value', 'Value'),
}))
});
}

return { ContainerOverrides: ret };
}

function extractOptional(obj: any, srcKey: string, dstKey: string) {
if ((obj[srcKey] !== undefined) && (obj[srcKey + 'Path'] !== undefined)) {
throw new Error(`Supply only one of '${srcKey}' or '${srcKey}Path'`);
Expand Down
Loading

0 comments on commit 7766d0e

Please sign in to comment.