Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(integ-tests): add IntegTest to group test cases #20015

Merged
merged 4 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions packages/@aws-cdk/integ-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ certain handler:

```ts
interface StackUnderTestProps extends StackProps {
functionProps?: lambda.FunctionProps;
architecture?: lambda.Architecture;
}

class StackUnderTest extends Stack {
Expand All @@ -34,7 +34,7 @@ class StackUnderTest extends Stack {
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')),
...props.functionProps,
architecture: props.architecture,
});
}
}
Expand Down Expand Up @@ -67,7 +67,8 @@ class StackUnderTest extends Stack {
const app = new App();

const stack = new Stack(app, 'stack');
new IntegTestCase(stack, 'DifferentArchitectures', {

const differentArchsCase = new IntegTestCase(stack, 'DifferentArchitectures', {
stacks: [
new StackUnderTest(app, 'Stack1', {
architecture: lambda.Architecture.ARM_64,
Expand All @@ -77,6 +78,13 @@ new IntegTestCase(stack, 'DifferentArchitectures', {
}),
],
});

// There must be exactly one instance of TestCase per file
new IntegTest(app, 'integ-test', {

// Register as many test cases as you want here
testCases: [differentArchsCase],
});
```

This is all the instruction you need for the integration test runner to know
Expand All @@ -90,7 +98,7 @@ const stackUnderTest = new Stack(app, 'StackUnderTest', /* ... */);

const stack = new Stack(app, 'stack');

new IntegTestCase(stack, 'CustomizedDeploymentWorkflow', {
const testCase = new IntegTestCase(stack, 'CustomizedDeploymentWorkflow', {
stacks: [stackUnderTest],
diffAssets: true,
stackUpdateWorkflow: true,
Expand All @@ -108,5 +116,9 @@ new IntegTestCase(stack, 'CustomizedDeploymentWorkflow', {
},
},
});

new IntegTest(app, 'integ-test', {
testCases: [testCase],
});
```

30 changes: 30 additions & 0 deletions packages/@aws-cdk/integ-tests/lib/manifest-synthesizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { IntegManifest, Manifest } from '@aws-cdk/cloud-assembly-schema';
import { ISynthesisSession } from '@aws-cdk/core';
import { IntegManifestWriter } from './manifest-writer';
import { IntegTestCase } from './test-case';

const emptyManifest: IntegManifest = {
version: '',
testCases: { },
};

export class IntegManifestSynthesizer {
constructor(private readonly testCases: IntegTestCase[]) {}

synthesize(session: ISynthesisSession) {
const manifest = this.testCases
.map(tc => tc.manifest)
.reduce(mergeManifests, emptyManifest);

const snapshotDir = session.assembly.outdir;

IntegManifestWriter.write(manifest, snapshotDir);
}
}

function mergeManifests(m1: IntegManifest, m2: IntegManifest): IntegManifest {
return {
version: Manifest.version(),
testCases: { ...m1.testCases, ...m2.testCases },
};
}
50 changes: 39 additions & 11 deletions packages/@aws-cdk/integ-tests/lib/test-case.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IntegManifest, TestCase, TestOptions } from '@aws-cdk/cloud-assembly-schema';
import { attachCustomSynthesis, ISynthesisSession, Stack } from '@aws-cdk/core';
import { IntegManifestWriter } from './manifest-writer';
import { IntegManifest, Manifest, TestCase, TestOptions } from '@aws-cdk/cloud-assembly-schema';
import { attachCustomSynthesis, Stack, ISynthesisSession } from '@aws-cdk/core';
import { IntegManifestSynthesizer } from './manifest-synthesizer';

// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
Expand All @@ -21,18 +21,46 @@ export interface IntegTestCaseProps extends TestOptions {
* apply to all stacks under this case.
*/
export class IntegTestCase extends Construct {
constructor(scope: Construct, id: string, props: IntegTestCaseProps) {
constructor(scope: Construct, private readonly id: string, private readonly props: IntegTestCaseProps) {
super(scope, id);
}

/**
* The integration test manifest for this test case. Manifests are used
* by the integration test runner.
*/
get manifest(): IntegManifest {
return {
version: Manifest.version(),
testCases: { [this.id]: toTestCase(this.props) },
};
}
}

/**
* Integration test properties
*/
export interface IntegTestProps {
/**
* List of test cases that make up this test
*/
readonly testCases: IntegTestCase[];
}

/**
* A collection of test cases. Each test case file should contain exactly one
* instance of this class.
*/
export class IntegTest extends Construct {
constructor(scope: Construct, id: string, private readonly props: IntegTestProps) {
super(scope, id);
}

protected onPrepare(): void {
attachCustomSynthesis(this, {
onSynthesize: (session: ISynthesisSession) => {
const snapshotDir = session.assembly.outdir;
const manifest: IntegManifest = {
version: '',
testCases: { [id]: toTestCase(props) },
};

IntegManifestWriter.write(manifest, snapshotDir);
const synthesizer = new IntegManifestSynthesizer(this.props.testCases);
synthesizer.synthesize(session);
},
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/integ-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"dependencies": {
"@aws-cdk/cloud-assembly-schema": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
"constructs": "^3.3.69"
},
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/integ-tests/rosetta/default.ts-fixture
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as lambda from '@aws-cdk/aws-lambda';
import { IntegTestCase } from '@aws-cdk/integ-tests';
import { IntegTestCase, IntegTest } from '@aws-cdk/integ-tests';
import {
App,
Construct,
Expand Down
45 changes: 45 additions & 0 deletions packages/@aws-cdk/integ-tests/test/manifest-synthesizer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { App, Stack } from '@aws-cdk/core';
import { CloudAssemblyBuilder } from '@aws-cdk/cx-api';
import { IntegTestCase } from '../lib';
import { IntegManifestSynthesizer } from '../lib/manifest-synthesizer';
import { IntegManifestWriter } from '../lib/manifest-writer';

describe(IntegManifestSynthesizer, () => {
it('synthesizes a multiple manifests', () => {
const write = jest.spyOn(IntegManifestWriter, 'write');

const app = new App();
const stack = new Stack(app, 'stack');
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cdk-test'));
const assembly = new CloudAssemblyBuilder(tmpDir);

const synthesizer = new IntegManifestSynthesizer([
new IntegTestCase(stack, 'case1', {
stacks: [new Stack(app, 'stack-under-test-1')],
}),
new IntegTestCase(stack, 'case2', {
stacks: [new Stack(app, 'stack-under-test-2')],
}),
]);

synthesizer.synthesize({
assembly,
outdir: 'asdas',
});

expect(write).toHaveBeenCalledWith({
version: '17.0.0',
testCases: {
case1: {
stacks: ['stack-under-test-1'],
},
case2: {
stacks: ['stack-under-test-2'],
},
},
}, tmpDir);
});
});