diff --git a/packages/@aws-cdk/integ-runner/.eslintrc.js b/packages/@aws-cdk/integ-runner/.eslintrc.js index 2658ee8727166..934540549e665 100644 --- a/packages/@aws-cdk/integ-runner/.eslintrc.js +++ b/packages/@aws-cdk/integ-runner/.eslintrc.js @@ -1,3 +1,4 @@ const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +baseConfig.ignorePatterns = [...baseConfig.ignorePatterns, "test/language-tests/**/integ.*.ts"]; module.exports = baseConfig; diff --git a/packages/@aws-cdk/integ-runner/README.md b/packages/@aws-cdk/integ-runner/README.md index bfe58e2ff4926..5230dc022a7b0 100644 --- a/packages/@aws-cdk/integ-runner/README.md +++ b/packages/@aws-cdk/integ-runner/README.md @@ -70,16 +70,32 @@ to be a self contained CDK app. The runner will execute the following for each f If this is set to `true` then the [update workflow](#update-workflow) will be disabled - `--app` The custom CLI command that will be used to run the test files. You can include {filePath} to specify where in the command the test file path should be inserted. Example: --app="python3.8 {filePath}". + + Use together with `--test-regex` to fully customize how tests are run, or use with a single `--language` preset to change the command used for this language. - `--test-regex` Detect integration test files matching this JavaScript regex pattern. If used multiple times, all files matching any one of the patterns are detected. - + + Use together with `--app` to fully customize how tests are run, or use with a single `--language` preset to change which files are detected for this language. +- `--language` + The language presets to use. You can discover and run tests written in multiple languages by passing this flag multiple times (`--language javascript --language typescript`). Defaults to all supported languages. Currently supported language presets are: + - `javascript`: + - File RegExp: `^integ\..*\.js$` + - App run command: `node {filePath}` + - `typescript`:\ + Note that for TypeScript files compiled to JavaScript, the JS tests will take precedence and the TS ones won't be evaluated. + - File RegExp: `^integ\..*(? { + if (!fileName) { + return {}; + } + + try { + return JSON.parse(fs.readFileSync(fileName, { encoding: 'utf-8' })); + } catch { + return {}; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts b/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts index fa4d64a4d3876..58fb75f2c965b 100644 --- a/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts +++ b/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts @@ -159,41 +159,118 @@ export interface IntegrationTestsDiscoveryOptions { readonly tests?: string[]; /** - * Detect integration test files matching any of these JavaScript regex patterns. - * - * @default - */ - readonly testRegex?: string[]; - - /** - * The CLI command used to run this test. - * If it contains {filePath}, the test file names will be substituted at that place in the command for each run. + * A map of of the app commands to run integration tests with, + * and the regex patterns matching the integration test files each app command. * - * @default - test run command will be `node {filePath}` + * If the app command contains {filePath}, the test file names will be substituted at that place in the command for each run. */ - readonly app?: string; + readonly testCases: { + [app: string]: string[] + } } - /** - * Discover integration tests + * Returns the name of the Python executable for the current OS */ -export class IntegrationTests { +function pythonExecutable() { + let python = 'python3'; + if (process.platform === 'win32') { + python = 'python'; + } + return python; +} + +export class IntegrationTestsDiscovery { /** - * Return configuration options from a file + * Get integration tests discovery options from CLI options */ - public static configFromFile(fileName?: string): Record { - if (!fileName) { - return {}; + public static fromCliOptions(options: { + app?: string; + exclude?: boolean, + language?: string[], + testRegex?: string[], + tests?: string[], + }): IntegrationTestsDiscoveryOptions { + const baseOptions = { + tests: options.tests, + exclude: options.exclude, + }; + + // Explicitly set both, app and test-regex + if (options.app && options.testRegex) { + return { + testCases: { + [options.app]: options.testRegex, + }, + ...baseOptions, + }; + } + + // Use the selected presets + if (!options.app && !options.testRegex) { + return { + testCases: this.getLanguagePresets(options.language), + ...baseOptions, + }; } - try { - return JSON.parse(fs.readFileSync(fileName, { encoding: 'utf-8' })); - } catch { - return {}; + // Only one of app or test-regex is set, with a single preset selected + // => override either app or test-regex + if (options.language?.length === 1) { + const [presetApp, presetTestRegex] = this.getLanguagePreset(options.language[0]); + return { + testCases: { + [options.app ?? presetApp]: options.testRegex ?? presetTestRegex, + }, + ...baseOptions, + }; } + + // Only one of app or test-regex is set, with multiple presets + // => impossible to resolve + const option = options.app ? '--app' : '--test-regex'; + throw new Error(`Only a single "--language" can be used with "${option}". Alternatively provide both "--app" and "--test-regex" to fully customize the configuration.`); } + /** + * Get the default configuration for a language + */ + private static getLanguagePreset(language: string) { + const languagePresets: { + [language: string]: [string, string[]] + } = { + javascript: ['node {filePath}', ['^integ\\..*\\.js$']], + typescript: ['node -r ts-node/register {filePath}', ['^integ\\.(?!.*\\.d\\.ts$).*\\.ts$']], + python: [`${pythonExecutable()} {filePath}`, ['^integ_.*\\.py$']], + csharp: ['dotnet run --project {filePath}', ['^Integ.*\\.csproj$']], + fsharp: ['dotnet run --project {filePath}', ['^Integ.*\\.fsproj$']], + // these are still unconfirmed and need testing + go: ['go mod download && go run {filePath}', ['^integ_.*\\.go$']], + java: ['mvn -e -q compile exec:java', ['^Integ.*\\.java$']], + }; + + return languagePresets[language]; + } + + /** + * Get the config for all selected languages + */ + private static getLanguagePresets(languages: string[] = []) { + return Object.fromEntries( + languages + .map(language => this.getLanguagePreset(language)) + .filter(Boolean), + ); + } + + private constructor() {} +} + + +/** + * Discover integration tests + */ +export class IntegrationTests { constructor(private readonly directory: string) { } @@ -209,7 +286,6 @@ export class IntegrationTests { return discoveredTests; } - const allTests = discoveredTests.filter(t => { const matches = requestedTests.some(pattern => t.matches(pattern)); return matches !== !!exclude; // Looks weird but is equal to (matches && !exclude) || (!matches && exclude) @@ -237,29 +313,21 @@ export class IntegrationTests { * @param tests Tests to include or exclude, undefined means include all tests. * @param exclude Whether the 'tests' list is inclusive or exclusive (inclusive by default). */ - public async fromCliArgs(options: IntegrationTestsDiscoveryOptions = {}): Promise { - return this.discover(options); - } - - private async discover(options: IntegrationTestsDiscoveryOptions): Promise { - const patterns = options.testRegex ?? ['^integ\\..*\\.js$']; - + public async discover(options: IntegrationTestsDiscoveryOptions): Promise { const files = await this.readTree(); - const integs = files.filter(fileName => patterns.some((p) => { - const regex = new RegExp(p); - return regex.test(fileName) || regex.test(path.basename(fileName)); - })); - - return this.request(integs, options); - } - - private request(files: string[], options: IntegrationTestsDiscoveryOptions): IntegTest[] { - const discoveredTests = files.map(fileName => new IntegTest({ - discoveryRoot: this.directory, - fileName, - appCommand: options.app, - })); + const discoveredTests = Object.entries(options.testCases) + .flatMap(([appCommand, patterns]) => files + .filter(fileName => patterns.some((pattern) => { + const regex = new RegExp(pattern); + return regex.test(fileName) || regex.test(path.basename(fileName)); + })) + .map(fileName => new IntegTest({ + discoveryRoot: this.directory, + fileName, + appCommand, + })), + ); return this.filterTests(discoveredTests, options.tests, options.exclude); } diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json index a68ebd429ee39..6aabd8a47d166 100644 --- a/packages/@aws-cdk/integ-runner/package.json +++ b/packages/@aws-cdk/integ-runner/package.json @@ -14,6 +14,7 @@ "awslint": "cdk-awslint", "pkglint": "pkglint -f", "test": "cdk-test", + "integ": "integ-runner", "watch": "cdk-watch", "build+test": "yarn build && yarn test", "build+test+package": "yarn build+test && yarn package", @@ -52,15 +53,19 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", - "@types/mock-fs": "^4.13.1", - "mock-fs": "^4.14.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^27.5.2", + "@types/mock-fs": "^4.13.1", "@types/node": "^14.18.34", "@types/workerpool": "^6.1.0", "@types/yargs": "^15.0.14", - "jest": "^27.5.1" + "constructs": "^10.0.0", + "mock-fs": "^4.14.0", + "jest": "^27.5.1", + "ts-node": "^10.9.1" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/integ-runner/test/cli.test.ts b/packages/@aws-cdk/integ-runner/test/cli.test.ts index 87bfabd0e7e78..8edc4b69d663a 100644 --- a/packages/@aws-cdk/integ-runner/test/cli.test.ts +++ b/packages/@aws-cdk/integ-runner/test/cli.test.ts @@ -4,14 +4,21 @@ import * as path from 'path'; import { main, parseCliArgs } from '../lib/cli'; let stdoutMock: jest.SpyInstance; +let stderrMock: jest.SpyInstance; beforeEach(() => { stdoutMock = jest.spyOn(process.stdout, 'write').mockImplementation(() => { return true; }); + stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); }); afterEach(() => { + stdoutMock.mockReset(); + stderrMock.mockReset(); +}); +afterAll(() => { stdoutMock.mockRestore(); + stderrMock.mockRestore(); }); -describe('CLI', () => { +describe('Test discovery', () => { const currentCwd = process.cwd(); beforeAll(() => { process.chdir(path.join(__dirname, '..')); @@ -28,7 +35,7 @@ describe('CLI', () => { }); test('find by custom pattern', async () => { - await main(['--list', '--directory=test/test-data', '--test-regex="^xxxxx\.integ-test[12]\.js$"']); + await main(['--list', '--directory=test/test-data', '--language=javascript', '--test-regex="^xxxxx\.integ-test[12]\.js$"']); expect(stdoutMock.mock.calls).toEqual([[ [ @@ -40,7 +47,14 @@ describe('CLI', () => { }); test('list only shows explicitly provided tests', async () => { - await main(['xxxxx.integ-test1.js', 'xxxxx.integ-test2.js', '--list', '--directory=test/test-data', '--test-regex="^xxxxx\..*\.js$"']); + await main([ + 'xxxxx.integ-test1.js', + 'xxxxx.integ-test2.js', + '--list', + '--directory=test/test-data', + '--language=javascript', + '--test-regex="^xxxxx\..*\.js$"', + ]); expect(stdoutMock.mock.calls).toEqual([[ [ @@ -51,11 +65,57 @@ describe('CLI', () => { ]]); }); + test('find only TypeScript files', async () => { + await main(['--list', '--language', 'typescript', '--directory=test']); + + expect(stdoutMock.mock.calls).toEqual([[ + 'language-tests/integ.typescript-test.ts\n', + ]]); + }); + test('can run with no tests detected', async () => { await main(['whatever.js', '--directory=test/test-data']); expect(stdoutMock.mock.calls).toEqual([]); }); + + test('app and test-regex override default presets', async () => { + await main([ + '--list', + '--directory=test/test-data', + '--app="node {filePath}"', + '--test-regex="^xxxxx\.integ-test[12]\.js$"', + ]); + + expect(stdoutMock.mock.calls).toEqual([[ + [ + 'xxxxx.integ-test1.js', + 'xxxxx.integ-test2.js', + '', + ].join('\n'), + ]]); + }); + + + test('cannot use --test-regex by itself with more than one language preset', async () => { + await expect(() => main([ + '--list', + '--directory=test/test-data', + '--language=javascript', + '--language=typescript', + '--test-regex="^xxxxx\.integ-test[12]\.js$"', + ])).rejects.toThrowError('Only a single "--language" can be used with "--test-regex". Alternatively provide both "--app" and "--test-regex" to fully customize the configuration.'); + }); + + test('cannot use --app by itself with more than one language preset', async () => { + await expect(() => main([ + '--list', + '--directory=test/test-data', + '--language=javascript', + '--language=typescript', + '--app="node --prof {filePath}"', + ])).rejects.toThrowError('Only a single "--language" can be used with "--app". Alternatively provide both "--app" and "--test-regex" to fully customize the configuration.'); + }); }); describe('CLI config file', () => { diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts new file mode 100644 index 0000000000000..1dd2461fe5966 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts @@ -0,0 +1,9 @@ +import { App, Stack } from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; + +const app = new App(); +const stack = new Stack(app); + +new IntegTest(app, 'Integ', { testCases: [stack] }); + +app.synth(); diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.assets.json new file mode 100644 index 0000000000000..7a4dc2dd27d68 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "Default.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/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/Default.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/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json new file mode 100644 index 0000000000000..d38b919332d46 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegDefaultTestDeployAssert4E6713E1.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/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/IntegDefaultTestDeployAssert4E6713E1.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/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/cdk.out new file mode 100644 index 0000000000000..145739f539580 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/integ.json new file mode 100644 index 0000000000000..6ed6bfc2ec111 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "22.0.0", + "testCases": { + "Integ/DefaultTest": { + "stacks": [ + "Default" + ], + "assertionStack": "Integ/DefaultTest/DeployAssert", + "assertionStackName": "IntegDefaultTestDeployAssert4E6713E1" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/manifest.json new file mode 100644 index 0000000000000..7a66047e6cf6f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/manifest.json @@ -0,0 +1,105 @@ +{ + "version": "22.0.0", + "artifacts": { + "Default.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "Default.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "Default": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "Default.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": [ + "Default.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": [ + "Default.assets" + ], + "metadata": { + "/Default/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Default/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Default" + }, + "IntegDefaultTestDeployAssert4E6713E1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegDefaultTestDeployAssert4E6713E1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegDefaultTestDeployAssert4E6713E1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegDefaultTestDeployAssert4E6713E1.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": [ + "IntegDefaultTestDeployAssert4E6713E1.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": [ + "IntegDefaultTestDeployAssert4E6713E1.assets" + ], + "metadata": { + "/Integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Integ/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/tree.json new file mode 100644 index 0000000000000..f2afbff888f8e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/tree.json @@ -0,0 +1,101 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Default": { + "id": "Default", + "path": "Default", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Default/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Default/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "Integ": { + "id": "Integ", + "path": "Integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py new file mode 100644 index 0000000000000..3f9e332afd906 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py @@ -0,0 +1,9 @@ +import aws_cdk as cdk +from aws_cdk.integ_tests_alpha import IntegTest + +app = cdk.App() +stack = cdk.Stack(app) + +IntegTest(app, "Integ", test_cases=[stack]) + +app.synth() \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.assets.json new file mode 100644 index 0000000000000..7a4dc2dd27d68 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "Default.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/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/Default.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/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json new file mode 100644 index 0000000000000..d38b919332d46 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegDefaultTestDeployAssert4E6713E1.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/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/IntegDefaultTestDeployAssert4E6713E1.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/integ-runner/test/language-tests/integ_python-test.py.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/cdk.out new file mode 100644 index 0000000000000..145739f539580 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/integ.json new file mode 100644 index 0000000000000..6ed6bfc2ec111 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "22.0.0", + "testCases": { + "Integ/DefaultTest": { + "stacks": [ + "Default" + ], + "assertionStack": "Integ/DefaultTest/DeployAssert", + "assertionStackName": "IntegDefaultTestDeployAssert4E6713E1" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/manifest.json new file mode 100644 index 0000000000000..7a66047e6cf6f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/manifest.json @@ -0,0 +1,105 @@ +{ + "version": "22.0.0", + "artifacts": { + "Default.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "Default.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "Default": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "Default.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": [ + "Default.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": [ + "Default.assets" + ], + "metadata": { + "/Default/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Default/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Default" + }, + "IntegDefaultTestDeployAssert4E6713E1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegDefaultTestDeployAssert4E6713E1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegDefaultTestDeployAssert4E6713E1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegDefaultTestDeployAssert4E6713E1.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": [ + "IntegDefaultTestDeployAssert4E6713E1.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": [ + "IntegDefaultTestDeployAssert4E6713E1.assets" + ], + "metadata": { + "/Integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Integ/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/tree.json new file mode 100644 index 0000000000000..783ace088df44 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/tree.json @@ -0,0 +1,101 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Default": { + "id": "Default", + "path": "Default", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Default/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.55.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Default/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.55.0" + } + }, + "Integ": { + "id": "Integ", + "path": "Integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.55.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.55.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.55.0-alpha.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.55.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts index d4055eaad76fc..0e5abd08738f5 100644 --- a/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts +++ b/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts @@ -548,7 +548,7 @@ describe('IntegTest runIntegTests', () => { })); }); - test('with custom app run command for JavaScript', () => { + test('with custom app run command', () => { // WHEN const integTest = new IntegTestRunner({ cdk: cdkMock.cdk, diff --git a/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts index 010377436b8f0..4ec141b45aa3c 100644 --- a/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts +++ b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts @@ -1,7 +1,7 @@ import * as mockfs from 'mock-fs'; -import { IntegrationTests } from '../../lib/runner/integration-tests'; +import { IntegrationTests, IntegrationTestsDiscovery } from '../../lib/runner/integration-tests'; -describe('IntegrationTests', () => { +describe('IntegrationTests Discovery', () => { const tests = new IntegrationTests('test'); let stderrMock: jest.SpyInstance; stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); @@ -9,84 +9,110 @@ describe('IntegrationTests', () => { beforeEach(() => { mockfs({ 'test/test-data': { - 'integ.integ-test1.js': 'content', - 'integ.integ-test2.js': 'content', - 'integ.integ-test3.js': 'content', - 'integration.test.js': 'should not match', + 'integ.test1.js': 'javascript', + 'integ.test2.js': 'javascript', + 'integ.test3.js': 'javascript', + 'integration.test.js': 'javascript-no-match', + + 'integ.test1.ts': 'typescript', + 'integ.test2.ts': 'typescript', + 'integ.test3.ts': 'typescript', + 'integ.test3.d.ts': 'typescript-no-match', + 'integration.test.ts': 'typescript-no-match', + + 'integ_test1.py': 'python', + 'integ_test2.py': 'python', + 'integ_test3.py': 'python', + 'integ.integ-test.py': 'python-no-match', }, 'other/other-data': { - 'integ.other-test1.js': 'content', + 'integ.other-test1.js': 'javascript', + 'integ.other-test1.ts': 'typescript', + 'integ_other-test1.py': 'python', }, }); }); afterEach(() => { mockfs.restore(); + stderrMock.mockReset(); }); - describe('from cli args', () => { - test('find all', async () => { - const integTests = await tests.fromCliArgs(); - - expect(integTests.length).toEqual(3); - expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.integ-test1.js$/)); - expect(integTests[1].fileName).toEqual(expect.stringMatching(/integ.integ-test2.js$/)); - expect(integTests[2].fileName).toEqual(expect.stringMatching(/integ.integ-test3.js$/)); - }); - - - test('find named tests', async () => { - const integTests = await tests.fromCliArgs({ tests: ['test-data/integ.integ-test1.js'] }); - - expect(integTests.length).toEqual(1); - expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.integ-test1.js$/)); - }); - - - test('test not found', async () => { - const integTests = await tests.fromCliArgs({ tests: ['test-data/integ.integ-test16.js'] }); - - expect(integTests.length).toEqual(0); - expect(stderrMock.mock.calls[0][0]).toContain( - 'No such integ test: test-data/integ.integ-test16.js', - ); - expect(stderrMock.mock.calls[1][0]).toContain( - 'Available tests: test-data/integ.integ-test1.js test-data/integ.integ-test2.js test-data/integ.integ-test3.js', - ); + describe.each([ + ['javascript', 'js', 'integ.test1.js'], + ['typescript', 'ts', 'integ.test1.ts'], + ['python', 'py', 'integ_test1.py'], + ])('%s', (language, fileExtension, namedTest) => { + const discoveryOptions = IntegrationTestsDiscovery.fromCliOptions({ + language: [language], }); - test('exclude tests', async () => { - const integTests = await tests.fromCliArgs({ tests: ['test-data/integ.integ-test1.js'], exclude: true }); - - const fileNames = integTests.map(test => test.fileName); - expect(integTests.length).toEqual(2); - expect(fileNames).not.toContain( - 'test/test-data/integ.integ-test1.js', - ); + test('assert test inputs', () => { + expect(namedTest).toContain('.' + fileExtension); }); - test('match regex', async () => { - const integTests = await tests.fromCliArgs({ testRegex: ['1\.js$', '2\.js'] }); - - expect(integTests.length).toEqual(2); - expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.integ-test1.js$/)); - expect(integTests[1].fileName).toEqual(expect.stringMatching(/integ.integ-test2.js$/)); - }); - - test('match regex with path', async () => { - const otherTestDir = new IntegrationTests('.'); - const integTests = await otherTestDir.fromCliArgs({ testRegex: ['other-data/integ\..*\.js$'] }); - - expect(integTests.length).toEqual(1); - expect(integTests[0].fileName).toEqual(expect.stringMatching(/integ.other-test1.js$/)); - }); - - test('can set app command', async () => { - const otherTestDir = new IntegrationTests('test'); - const integTests = await otherTestDir.fromCliArgs({ app: 'node --no-warnings {filePath}' }); - - expect(integTests.length).toEqual(3); - expect(integTests[0].appCommand).toEqual('node --no-warnings {filePath}'); + describe('from cli args', () => { + test('find all', async () => { + const integTests = await tests.discover(discoveryOptions); + + expect(integTests.length).toEqual(3); + expect(integTests[0].fileName).toEqual(expect.stringMatching(new RegExp(`^.*test1\\.${fileExtension}$`))); + expect(integTests[1].fileName).toEqual(expect.stringMatching(new RegExp(`^.*test2\\.${fileExtension}$`))); + expect(integTests[2].fileName).toEqual(expect.stringMatching(new RegExp(`^.*test3\\.${fileExtension}$`))); + }); + + test('find named tests', async () => { + const integTests = await tests.discover({ ...discoveryOptions, tests: [`test-data/${namedTest}`] }); + + expect(integTests.length).toEqual(1); + expect(integTests[0].fileName).toEqual(expect.stringMatching(namedTest)); + }); + + + test('test not found', async () => { + const integTests = await tests.discover({ ...discoveryOptions, tests: [`test-data/${namedTest}`.replace('test1', 'test42')] }); + + expect(integTests.length).toEqual(0); + expect(stderrMock.mock.calls[0][0].trim()).toMatch( + new RegExp(`No such integ test: test-data\\/.*test42\\.${fileExtension}`), + ); + expect(stderrMock.mock.calls[1][0]).toMatch( + new RegExp(`Available tests: test-data\\/.*test1\\.${fileExtension} test-data\\/.*test2\\.${fileExtension} test-data\\/.*test3\\.${fileExtension}`), + ); + }); + + test('exclude tests', async () => { + const integTests = await tests.discover({ ...discoveryOptions, tests: [`test-data/${namedTest}`], exclude: true }); + + const fileNames = integTests.map(test => test.fileName); + expect(integTests.length).toEqual(2); + expect(fileNames).not.toContain( + `test/test-data/${namedTest}`, + ); + }); + + test('match regex', async () => { + const integTests = await tests.discover(IntegrationTestsDiscovery.fromCliOptions({ + language: [language], + testRegex: [`[12]\\.${fileExtension}$`], + })); + + expect(integTests.length).toEqual(2); + expect(integTests[0].fileName).toEqual(expect.stringMatching(new RegExp(`1\\.${fileExtension}$`))); + expect(integTests[1].fileName).toEqual(expect.stringMatching(new RegExp(`2\\.${fileExtension}$`))); + }); + + test('match regex with path', async () => { + const otherTestDir = new IntegrationTests('.'); + const integTests = await otherTestDir.discover(IntegrationTestsDiscovery.fromCliOptions({ + language: [language], + testRegex: [`other-data/integ.*\\.${fileExtension}$`], + })); + + expect(integTests.length).toEqual(1); + expect(integTests[0].fileName).toEqual(expect.stringMatching(new RegExp(`.*other-test1\\.${fileExtension}$`))); + }); }); }); }); + diff --git a/packages/@aws-cdk/integ-runner/tsconfig.json b/packages/@aws-cdk/integ-runner/tsconfig.json index 602608087631f..f8f20f4a3ec44 100644 --- a/packages/@aws-cdk/integ-runner/tsconfig.json +++ b/packages/@aws-cdk/integ-runner/tsconfig.json @@ -15,14 +15,14 @@ "resolveJsonModule": true, "composite": true, "incremental": true - }, + }, "include": [ "**/*.ts", "**/*.d.ts", "lib/init-templates/*/*/add-project.hook.ts" ], "exclude": [ - "lib/init-templates/*/typescript/**/*.ts" + "lib/init-templates/*/typescript/**/*.ts", + "test/language-tests/**/integ.*.ts" ] } -