diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 50d107df1..b7a893ddc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,7 @@ jobs: publish-aws-cdk-cli-lib-alpha: ${{ steps.check-publish-aws-cdk-cli-lib-alpha.outputs.publish }} publish-aws-cdk-toolkit-lib: ${{ steps.check-publish-aws-cdk-toolkit-lib.outputs.publish }} publish-cdk: ${{ steps.check-publish-cdk.outputs.publish }} + publish-aws-cdk-integ-runner: ${{ steps.check-publish-aws-cdk-integ-runner.outputs.publish }} env: CI: "true" steps: @@ -61,6 +62,9 @@ jobs: - id: check-publish-cdk run: (git ls-remote -q --exit-code --tags origin $(cat dist/releasetag.txt) && (echo "publish=false" >> $GITHUB_OUTPUT)) || echo "publish=true" >> $GITHUB_OUTPUT working-directory: packages/cdk + - id: check-publish-aws-cdk-integ-runner + run: (git ls-remote -q --exit-code --tags origin $(cat dist/releasetag.txt) && (echo "publish=false" >> $GITHUB_OUTPUT)) || echo "publish=true" >> $GITHUB_OUTPUT + working-directory: packages/@aws-cdk/integ-runner - name: Output the sha value that downstream checks expect id: git_remote run: echo "latest_commit=${{ github.sha }}" >> $GITHUB_OUTPUT @@ -160,6 +164,18 @@ jobs: name: cdk_build-artifact path: packages/cdk/dist overwrite: true + - name: "@aws-cdk/integ-runner: Backup artifact permissions" + if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} + run: cd dist && getfacl -R . > permissions-backup.acl + continue-on-error: true + working-directory: packages/@aws-cdk/integ-runner + - name: "@aws-cdk/integ-runner: Upload artifact" + if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} + uses: actions/upload-artifact@v4.4.0 + with: + name: aws-cdk-integ-runner_build-artifact + path: packages/@aws-cdk/integ-runner/dist + overwrite: true - name: "standalone: Upload artifact" if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} uses: actions/upload-artifact@v4.4.0 @@ -980,6 +996,60 @@ jobs: NPM_CONFIG_PROVENANCE: "true" NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: npx -p publib@latest publib-npm + aws-cdk-integ-runner_release_github: + name: "@aws-cdk/integ-runner: Publish to GitHub Releases" + needs: + - release + - aws-cdk-integ-runner_release_npm + runs-on: ubuntu-latest + permissions: + contents: write + if: ${{ needs.release.outputs.latest_commit == github.sha && needs.release.outputs.publish-aws-cdk-integ-runner == 'true' }} + steps: + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: aws-cdk-integ-runner_build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_REF: ${{ github.sha }} + run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) --target $GITHUB_REF 2> $errout && true; exitcode=$?; if [ $exitcode -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then cat $errout; exit $exitcode; fi + aws-cdk-integ-runner_release_npm: + name: "@aws-cdk/integ-runner: Publish to npm" + needs: release + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + if: ${{ needs.release.outputs.latest_commit == github.sha && needs.release.outputs.publish-aws-cdk-integ-runner == 'true' }} + steps: + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: aws-cdk-integ-runner_build-artifact + path: dist + - name: Restore build artifact permissions + run: cd dist && setfacl --restore=permissions-backup.acl + continue-on-error: true + - name: Release + env: + NPM_DIST_TAG: latest + NPM_REGISTRY: registry.npmjs.org + NPM_CONFIG_PROVENANCE: "true" + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npx -p publib@latest publib-npm standalone_release_adc: name: "standalone: publish to ADC" needs: release diff --git a/.projen/deps.json b/.projen/deps.json index 7fe9e8100..8e2a0a33b 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -21,6 +21,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/.projenrc.ts b/.projenrc.ts index fbece9b4f..f22ebede5 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import { yarn, CdkCliIntegTestsWorkflow } from 'cdklabs-projen-project-types'; +import type { TypeScriptWorkspaceOptions } from 'cdklabs-projen-project-types/lib/yarn'; import * as pj from 'projen'; import { Stability } from 'projen/lib/cdk'; import { AdcPublishing } from './projenrc/adc-publishing'; @@ -33,7 +34,7 @@ function configureProject(x: A): A { x.addDevDeps( '@typescript-eslint/eslint-plugin@^8', '@typescript-eslint/parser@^8', - '@stylistic/eslint-plugin', + '@stylistic/eslint-plugin@^3', '@cdklabs/eslint-plugin', 'eslint-plugin-import', 'eslint-plugin-jest', @@ -86,6 +87,15 @@ const ADDITIONAL_CLI_IGNORE_PATTERNS = [ const CLI_SDK_V3_RANGE = '^3'; +const defaultTsOptions: NonNullable['compilerOptions'] = { + target: 'ES2020', + module: 'commonjs', + lib: ['es2020', 'dom'], + incremental: true, + esModuleInterop: false, + skipLibCheck: true, +}; + /** * Shared jest config * @@ -412,7 +422,7 @@ const cloudFormationDiff = configureProject( // (EDIT: or should it? We're going to bundle it into aws-cdk-lib) tsconfig: { compilerOptions: { - esModuleInterop: false, + ...defaultTsOptions, }, }, @@ -480,6 +490,11 @@ const yargsGen = configureProject( deps: ['@cdklabs/typewriter', 'prettier@^2.8', 'lodash.clonedeep'], devDeps: ['@types/semver', '@types/yarnpkg__lockfile', '@types/lodash.clonedeep', '@types/prettier@^2'], minNodeVersion: '17.0.0', // Necessary for 'structuredClone' + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); @@ -502,6 +517,11 @@ const nodeBundle = configureProject( }, }, }), + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); // Too many console statements @@ -521,6 +541,11 @@ const cliPluginContract = configureProject( ], devDeps: [ ], + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); @@ -574,21 +599,13 @@ const cdkAssets = configureProject( ], tsconfigDev: { compilerOptions: { - target: 'ES2020', - module: 'commonjs', - lib: ['es2020', 'dom'], - incremental: true, - esModuleInterop: false, + ...defaultTsOptions, }, include: ['bin/**/*.ts'], }, tsconfig: { compilerOptions: { - target: 'ES2020', - module: 'commonjs', - lib: ['es2020', 'dom'], - incremental: true, - esModuleInterop: false, + ...defaultTsOptions, rootDir: undefined, outDir: undefined, }, @@ -664,10 +681,10 @@ const tmpToolkitHelpers = configureProject( ], tsconfig: { compilerOptions: { + ...defaultTsOptions, target: 'es2022', - lib: ['es2022', 'esnext.disposable'], + lib: ['es2022', 'esnext.disposable', 'dom'], module: 'NodeNext', - esModuleInterop: false, }, }, }), @@ -787,6 +804,8 @@ const cli = configureProject( }, tsconfig: { compilerOptions: { + ...defaultTsOptions, + // Changes the meaning of 'import' for libraries whose top-level export is a function // 'aws-cdk' has been written against `false` for interop esModuleInterop: false, @@ -980,6 +999,11 @@ const cliLib = configureProject( moduleFileExtensions: undefined, }, }), + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); @@ -1152,10 +1176,10 @@ const toolkitLib = configureProject( }), tsconfig: { compilerOptions: { + ...defaultTsOptions, target: 'es2022', - lib: ['es2022', 'esnext.disposable'], + lib: ['es2022', 'esnext.disposable', 'dom'], module: 'NodeNext', - esModuleInterop: false, }, }, }), @@ -1278,7 +1302,7 @@ const cdkCliWrapper = configureProject( name: '@aws-cdk/cdk-cli-wrapper', description: 'CDK CLI Wrapper Library', srcdir: 'lib', - devDeps: ['aws-cdk-lib', cli, 'constructs', '@aws-cdk/integ-runner'], + devDeps: [], nextVersionCommand: `tsx ../../../projenrc/next-version.ts copyVersion:../../../${cliPackageJson}`, releasableCommits: transitiveToolkitPackages('@aws-cdk/cdk-cli-wrapper'), @@ -1289,15 +1313,23 @@ const cdkCliWrapper = configureProject( }, }, }), + + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); +/* Can't have this -- the integ-runner depends on this package (() => { const integ = cdkCliWrapper.addTask('integ', { exec: 'integ-runner --language javascript', }); cdkCliWrapper.testTask.spawn(integ); })(); +*/ ////////////////////////////////////////////////////////////////////// @@ -1311,12 +1343,114 @@ const cdkAliasPackage = configureProject( deps: [cli.customizeReference({ versionType: 'exact' })], nextVersionCommand: `tsx ../../projenrc/next-version.ts copyVersion:../../${cliPackageJson}`, releasableCommits: transitiveToolkitPackages('cdk'), + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, }), ); void cdkAliasPackage; ////////////////////////////////////////////////////////////////////// +const integRunner = configureProject( + new yarn.TypeScriptWorkspace({ + ...genericCdkProps(), + parent: repo, + name: '@aws-cdk/integ-runner', + description: 'CDK Integration Testing Tool', + srcdir: 'lib', + deps: [ + cloudAssemblySchema.customizeReference({ versionType: 'exact' }), + cxApi, + cdkCliWrapper.customizeReference({ versionType: 'exact' }), + cli.customizeReference({ versionType: 'exact' }), + cdkAssets.customizeReference({ versionType: 'exact' }), + cloudFormationDiff.customizeReference({ versionType: 'exact' }), + 'workerpool@^6', + 'chokidar@^3', + 'chalk@^4', + 'fs-extra@^9', + 'yargs@^16', + '@aws-cdk/aws-service-spec', + '@aws-sdk/client-cloudformation@^3', + ], + devDeps: [ + 'aws-cdk-lib', + '@types/fs-extra', + '@types/mock-fs@^4', + 'mock-fs@^5', + '@types/workerpool@^6', + '@types/yargs', + 'constructs@^10', + '@aws-cdk/integ-tests-alpha@2.184.1-alpha.0', + ], + allowPrivateDeps: true, + tsconfig: { + compilerOptions: { + ...defaultTsOptions, + }, + }, + jestOptions: jestOptionsForProject({ + jestConfig: { + coverageThreshold: { + branches: 79, + }, + }, + }), + }), +); +integRunner.gitignore?.addPatterns( + // Ignore this symlink, we recreate it at test time + 'test/test-archive-follow/data/linked', + + // These files are needed for unit tests + '!test/test-data/cdk-integ.out*/', + + '!**/*.snapshot/**/asset.*/*.js', + '!**/*.snapshot/**/asset.*/*.d.ts', + '!**/*.snapshot/**/asset.*/**', + + 'lib/recommended-feature-flags.json', +); +integRunner.tsconfig?.addInclude('lib/*.json'); +integRunner.tsconfig?.addInclude('lib/init-templates/*/*/add-project.hook.ts'); +integRunner.tsconfig?.addExclude('lib/init-templates/*/typescript/**/*.ts'); +integRunner.tsconfig?.addExclude('test/language-tests/**/integ.*.ts'); + +integRunner.preCompileTask.prependExec('./build-tools/generate.sh'); + +new BundleCli(integRunner, { + externals: { + optionalDependencies: [ + 'fsevents', + ], + dependencies: [ + '@aws-cdk/aws-service-spec', + 'aws-cdk', + ], + }, + allowedLicenses: [ + 'Apache-2.0', + 'MIT', + 'BSD-3-Clause', + 'ISC', + 'BSD-2-Clause', + '0BSD', + 'MIT OR Apache-2.0', + ], + dontAttribute: '^@aws-cdk/|^@cdklabs/|^cdk-assets$|^cdk-cli-wrapper$', + test: 'bin/integ-runner --version', + entryPoints: [ + 'lib/index.js', + 'lib/workers/extract/index.js', + ], + minifyWhitespace: true, +}); + +////////////////////////////////////////////////////////////////////// + // The pj.github.Dependabot component is only for a single Node project, // but we need multiple non-Node projects new pj.YamlFile(repo, '.github/dependabot.yml', { diff --git a/aws-cdk-cli.code-workspace b/aws-cdk-cli.code-workspace index 2b9750d09..15a3a5841 100644 --- a/aws-cdk-cli.code-workspace +++ b/aws-cdk-cli.code-workspace @@ -20,6 +20,9 @@ { "path": "packages/@aws-cdk/cloudformation-diff" }, + { + "path": "packages/@aws-cdk/integ-runner" + }, { "path": "packages/@aws-cdk/node-bundle" }, diff --git a/package.json b/package.json index 524d8ec12..e9f56673e 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@aws-sdk/credential-providers": "^3", "@aws-sdk/lib-storage": "^3", "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/node": "ts5.6", "@typescript-eslint/eslint-plugin": "^8", "@typescript-eslint/parser": "^8", @@ -69,7 +69,8 @@ "packages/@aws-cdk/cli-lib-alpha", "packages/@aws-cdk/toolkit-lib", "packages/@aws-cdk/cdk-cli-wrapper", - "packages/cdk" + "packages/cdk", + "packages/@aws-cdk/integ-runner" ], "nohoist": [ "@aws-cdk/cloud-assembly-schema/jsonschema", @@ -91,7 +92,8 @@ "/packages/@aws-cdk/cli-lib-alpha", "/packages/@aws-cdk/toolkit-lib", "/packages/@aws-cdk/cdk-cli-wrapper", - "/packages/cdk" + "/packages/cdk", + "/packages/@aws-cdk/integ-runner" ] }, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/@aws-cdk/cdk-cli-wrapper/.projen/deps.json b/packages/@aws-cdk/cdk-cli-wrapper/.projen/deps.json index 78023756e..4ab2c1692 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/.projen/deps.json +++ b/packages/@aws-cdk/cdk-cli-wrapper/.projen/deps.json @@ -1,15 +1,12 @@ { "dependencies": [ - { - "name": "@aws-cdk/integ-runner", - "type": "build" - }, { "name": "@cdklabs/eslint-plugin", "type": "build" }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { @@ -31,14 +28,6 @@ "version": "^8", "type": "build" }, - { - "name": "aws-cdk", - "type": "build" - }, - { - "name": "aws-cdk-lib", - "type": "build" - }, { "name": "constructs", "version": "^10.0.0", diff --git a/packages/@aws-cdk/cdk-cli-wrapper/.projen/tasks.json b/packages/@aws-cdk/cdk-cli-wrapper/.projen/tasks.json index 2c37ef366..710e4538b 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/.projen/tasks.json +++ b/packages/@aws-cdk/cdk-cli-wrapper/.projen/tasks.json @@ -37,7 +37,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@aws-cdk/integ-runner,@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,aws-cdk-lib,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,ts-jest" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,ts-jest" } ] }, @@ -77,7 +77,7 @@ "name": "gather-versions", "steps": [ { - "exec": "node -e \"require(require.resolve('cdklabs-projen-project-types/lib/yarn/gather-versions.exec.js')).cliMain()\" aws-cdk=exact", + "exec": "node -e \"require(require.resolve('cdklabs-projen-project-types/lib/yarn/gather-versions.exec.js')).cliMain()\" ", "receiveArgs": true } ] @@ -100,14 +100,6 @@ } ] }, - "integ": { - "name": "integ", - "steps": [ - { - "exec": "integ-runner --language javascript" - } - ] - }, "nx": { "name": "nx", "steps": [ @@ -139,9 +131,6 @@ }, { "spawn": "eslint" - }, - { - "spawn": "integ" } ] }, diff --git a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts index 14d0c4125..bf1668e72 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts @@ -56,7 +56,7 @@ export interface DeployOptions extends DefaultCdkOptions { /** * What kind of security changes require approval * - * @default RequireApproval.NEVER + * @default RequireApproval.Never */ readonly requireApproval?: RequireApproval; diff --git a/packages/@aws-cdk/cdk-cli-wrapper/package.json b/packages/@aws-cdk/cdk-cli-wrapper/package.json index f80f72cab..2335fb453 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/package.json +++ b/packages/@aws-cdk/cdk-cli-wrapper/package.json @@ -14,7 +14,6 @@ "default": "npx projen default", "eslint": "npx projen eslint", "gather-versions": "npx projen gather-versions", - "integ": "npx projen integ", "nx": "npx projen nx", "package": "npx projen package", "post-compile": "npx projen post-compile", @@ -31,27 +30,24 @@ "organization": true }, "devDependencies": { - "@aws-cdk/integ-runner": "^2.72.1", "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@typescript-eslint/eslint-plugin": "^8", "@typescript-eslint/parser": "^8", - "aws-cdk": "^0.0.0", - "aws-cdk-lib": "^2.181.1", "constructs": "^10.0.0", "eslint": "^9", - "eslint-config-prettier": "^10.0.2", - "eslint-import-resolver-typescript": "^3.8.3", + "eslint-config-prettier": "^10.1.1", + "eslint-import-resolver-typescript": "^4.2.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.11.0", - "eslint-plugin-jsdoc": "^50.6.3", + "eslint-plugin-jsdoc": "^50.6.8", "eslint-plugin-prettier": "^5.2.3", "jest": "^29.7.0", "jest-junit": "^16", "prettier": "^2.8", - "projen": "^0.91.13", + "projen": "^0.91.18", "ts-jest": "^29.2.6", "typescript": "5.6" }, diff --git a/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.dev.json b/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.dev.json index 6eacf69fe..c23fc6c66 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.dev.json +++ b/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, @@ -34,9 +37,5 @@ "exclude": [ "node_modules" ], - "references": [ - { - "path": "../../aws-cdk" - } - ] + "references": [] } diff --git a/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.json b/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.json index 20a6ec9f9..494d42c75 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.json +++ b/packages/@aws-cdk/cdk-cli-wrapper/tsconfig.json @@ -5,14 +5,15 @@ "outDir": "lib", "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,16 +26,14 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ "lib/**/*.ts" ], "exclude": [], - "references": [ - { - "path": "../../aws-cdk" - } - ] + "references": [] } diff --git a/packages/@aws-cdk/cli-lib-alpha/.projen/deps.json b/packages/@aws-cdk/cli-lib-alpha/.projen/deps.json index c0393ca2c..7221e9d4d 100644 --- a/packages/@aws-cdk/cli-lib-alpha/.projen/deps.json +++ b/packages/@aws-cdk/cli-lib-alpha/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/cli-lib-alpha/.projen/tasks.json b/packages/@aws-cdk/cli-lib-alpha/.projen/tasks.json index d23b1e928..c4b2788ca 100644 --- a/packages/@aws-cdk/cli-lib-alpha/.projen/tasks.json +++ b/packages/@aws-cdk/cli-lib-alpha/.projen/tasks.json @@ -52,7 +52,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,aws-cdk-lib,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,jsii-diff,jsii-pacmak,license-checker,projen,ts-jest" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,aws-cdk-lib,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,jsii-diff,jsii-pacmak,license-checker,projen,ts-jest" } ] }, diff --git a/packages/@aws-cdk/cli-lib-alpha/package.json b/packages/@aws-cdk/cli-lib-alpha/package.json index 9fab17e10..90e88efb2 100644 --- a/packages/@aws-cdk/cli-lib-alpha/package.json +++ b/packages/@aws-cdk/cli-lib-alpha/package.json @@ -40,7 +40,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@typescript-eslint/eslint-plugin": "^8", diff --git a/packages/@aws-cdk/cli-lib-alpha/tsconfig.dev.json b/packages/@aws-cdk/cli-lib-alpha/tsconfig.dev.json index bd61db60f..1f69e055f 100644 --- a/packages/@aws-cdk/cli-lib-alpha/tsconfig.dev.json +++ b/packages/@aws-cdk/cli-lib-alpha/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/cli-plugin-contract/.projen/deps.json b/packages/@aws-cdk/cli-plugin-contract/.projen/deps.json index 0fff4864e..408f6aa15 100644 --- a/packages/@aws-cdk/cli-plugin-contract/.projen/deps.json +++ b/packages/@aws-cdk/cli-plugin-contract/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/cli-plugin-contract/.projen/tasks.json b/packages/@aws-cdk/cli-plugin-contract/.projen/tasks.json index c5b2af9fd..5050021d3 100644 --- a/packages/@aws-cdk/cli-plugin-contract/.projen/tasks.json +++ b/packages/@aws-cdk/cli-plugin-contract/.projen/tasks.json @@ -51,7 +51,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest" } ] }, diff --git a/packages/@aws-cdk/cli-plugin-contract/package.json b/packages/@aws-cdk/cli-plugin-contract/package.json index 292addac5..35703426e 100644 --- a/packages/@aws-cdk/cli-plugin-contract/package.json +++ b/packages/@aws-cdk/cli-plugin-contract/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@typescript-eslint/eslint-plugin": "^8", diff --git a/packages/@aws-cdk/cli-plugin-contract/tsconfig.dev.json b/packages/@aws-cdk/cli-plugin-contract/tsconfig.dev.json index 18ee3a655..c23fc6c66 100644 --- a/packages/@aws-cdk/cli-plugin-contract/tsconfig.dev.json +++ b/packages/@aws-cdk/cli-plugin-contract/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/cli-plugin-contract/tsconfig.json b/packages/@aws-cdk/cli-plugin-contract/tsconfig.json index a9cd6a329..494d42c75 100644 --- a/packages/@aws-cdk/cli-plugin-contract/tsconfig.json +++ b/packages/@aws-cdk/cli-plugin-contract/tsconfig.json @@ -5,14 +5,15 @@ "outDir": "lib", "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/@aws-cdk/cloud-assembly-schema/.projen/deps.json b/packages/@aws-cdk/cloud-assembly-schema/.projen/deps.json index fffedbe99..824ba66e4 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.projen/deps.json +++ b/packages/@aws-cdk/cloud-assembly-schema/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/cloud-assembly-schema/.projen/tasks.json b/packages/@aws-cdk/cloud-assembly-schema/.projen/tasks.json index e26c2b307..889a70ae6 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.projen/tasks.json +++ b/packages/@aws-cdk/cloud-assembly-schema/.projen/tasks.json @@ -52,7 +52,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,@types/semver,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,jsii-diff,jsii-pacmak,license-checker,mock-fs,projen,ts-jest,tsx,typescript-json-schema,semver" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,@types/semver,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,jsii-diff,jsii-pacmak,license-checker,mock-fs,projen,ts-jest,tsx,typescript-json-schema,semver" } ] }, diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 4282e917a..1ce9eafd5 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -39,7 +39,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@types/semver": "^7.5.8", diff --git a/packages/@aws-cdk/cloudformation-diff/.projen/deps.json b/packages/@aws-cdk/cloudformation-diff/.projen/deps.json index 486d0e425..df727aa76 100644 --- a/packages/@aws-cdk/cloudformation-diff/.projen/deps.json +++ b/packages/@aws-cdk/cloudformation-diff/.projen/deps.json @@ -10,6 +10,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/cloudformation-diff/.projen/tasks.json b/packages/@aws-cdk/cloudformation-diff/.projen/tasks.json index cc14b1d47..320948e52 100644 --- a/packages/@aws-cdk/cloudformation-diff/.projen/tasks.json +++ b/packages/@aws-cdk/cloudformation-diff/.projen/tasks.json @@ -52,7 +52,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@aws-sdk/client-cloudformation,@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,license-checker,projen,ts-jest,@aws-cdk/aws-service-spec,@aws-cdk/service-spec-types,diff,fast-deep-equal" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@aws-sdk/client-cloudformation,@cdklabs/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,license-checker,projen,ts-jest,@aws-cdk/aws-service-spec,@aws-cdk/service-spec-types,diff,fast-deep-equal" } ] }, diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 4e444d3b5..1b8e7e504 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -33,7 +33,7 @@ "devDependencies": { "@aws-sdk/client-cloudformation": "^3.758.0", "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@typescript-eslint/eslint-plugin": "^8", @@ -57,7 +57,7 @@ "typescript": "5.6" }, "dependencies": { - "@aws-cdk/aws-service-spec": "^0.1.60", + "@aws-cdk/aws-service-spec": "^0.1.62", "@aws-cdk/service-spec-types": "^0.0.126", "chalk": "^4", "diff": "^7.0.0", diff --git a/packages/@aws-cdk/cloudformation-diff/tsconfig.dev.json b/packages/@aws-cdk/cloudformation-diff/tsconfig.dev.json index cea602da2..c23fc6c66 100644 --- a/packages/@aws-cdk/cloudformation-diff/tsconfig.dev.json +++ b/packages/@aws-cdk/cloudformation-diff/tsconfig.dev.json @@ -8,9 +8,10 @@ "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/cloudformation-diff/tsconfig.json b/packages/@aws-cdk/cloudformation-diff/tsconfig.json index 14c383d3d..494d42c75 100644 --- a/packages/@aws-cdk/cloudformation-diff/tsconfig.json +++ b/packages/@aws-cdk/cloudformation-diff/tsconfig.json @@ -10,9 +10,10 @@ "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/@aws-cdk/integ-runner/.eslintrc.js b/packages/@aws-cdk/integ-runner/.eslintrc.js new file mode 100644 index 000000000..8f296a38a --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.eslintrc.js @@ -0,0 +1,9 @@ +var path = require('path'); +var fs = require('fs'); +var contents = fs.readFileSync(`${__dirname}/.eslintrc.json`, { encoding: 'utf-8' }); +// Strip comments, JSON.parse() doesn't like those +contents = contents.replace(/^\/\/.*$/m, ''); +var json = JSON.parse(contents); +// Patch the .json config with something that can only be represented in JS +json.parserOptions.tsconfigRootDir = __dirname; +module.exports = json; \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/.eslintrc.json b/packages/@aws-cdk/integ-runner/.eslintrc.json new file mode 100644 index 000000000..8d4b0afed --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.eslintrc.json @@ -0,0 +1,320 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "env": { + "jest": true, + "node": true + }, + "root": true, + "plugins": [ + "@typescript-eslint", + "import", + "@cdklabs", + "@stylistic", + "jest", + "jsdoc" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "project": "./tsconfig.dev.json" + }, + "extends": [ + "plugin:import/typescript", + "plugin:jest/recommended", + "plugin:prettier/recommended" + ], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [ + ".ts", + ".tsx" + ] + }, + "import/resolver": { + "node": {}, + "typescript": { + "project": "./tsconfig.dev.json", + "alwaysTryTypes": true + } + } + }, + "ignorePatterns": [ + "*.js", + "*.d.ts", + "node_modules/", + "*.generated.ts", + "coverage", + "*.generated.ts" + ], + "rules": { + "@typescript-eslint/no-require-imports": [ + "error" + ], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": [ + "**/test/**", + "**/build-tools/**" + ], + "optionalDependencies": false, + "peerDependencies": true + } + ], + "import/no-unresolved": [ + "error" + ], + "import/order": [ + "error", + { + "groups": [ + "builtin", + "external" + ], + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "import/no-duplicates": "error", + "no-shadow": [ + "off" + ], + "@typescript-eslint/no-shadow": [ + "error" + ], + "key-spacing": [ + "error" + ], + "no-multiple-empty-lines": [ + "error", + { + "max": 1 + } + ], + "@typescript-eslint/no-floating-promises": [ + "error" + ], + "no-return-await": "off", + "@typescript-eslint/return-await": "error", + "no-trailing-spaces": [ + "error" + ], + "dot-notation": [ + "error" + ], + "no-bitwise": [ + "error" + ], + "@typescript-eslint/member-ordering": [ + "error", + { + "default": [ + "public-static-field", + "public-static-method", + "protected-static-field", + "protected-static-method", + "private-static-field", + "private-static-method", + "field", + "constructor", + "method" + ] + } + ], + "@cdklabs/no-core-construct": [ + "error" + ], + "@cdklabs/invalid-cfn-imports": [ + "error" + ], + "@cdklabs/no-literal-partition": [ + "error" + ], + "@cdklabs/no-invalid-path": [ + "error" + ], + "@cdklabs/promiseall-no-unbounded-parallelism": [ + "error" + ], + "no-throw-literal": [ + "error" + ], + "@stylistic/indent": [ + "error", + 2 + ], + "quotes": [ + "error", + "single", + { + "avoidEscape": true + } + ], + "@stylistic/member-delimiter-style": [ + "error" + ], + "@stylistic/comma-dangle": [ + "error", + "always-multiline" + ], + "@stylistic/no-extra-semi": [ + "error" + ], + "@stylistic/curly-newline": [ + "error", + "always" + ], + "comma-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "no-multi-spaces": [ + "error", + { + "ignoreEOLComments": false + } + ], + "array-bracket-spacing": [ + "error", + "never" + ], + "array-bracket-newline": [ + "error", + "consistent" + ], + "object-curly-spacing": [ + "error", + "always" + ], + "object-curly-newline": [ + "error", + { + "multiline": true, + "consistent": true + } + ], + "object-property-newline": [ + "error", + { + "allowAllPropertiesOnSameLine": true + } + ], + "keyword-spacing": [ + "error" + ], + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + "space-before-blocks": "error", + "curly": [ + "error", + "multi-line", + "consistent" + ], + "eol-last": [ + "error", + "always" + ], + "@stylistic/spaced-comment": [ + "error", + "always", + { + "exceptions": [ + "/", + "*" + ], + "markers": [ + "/" + ] + } + ], + "@stylistic/padded-blocks": [ + "error", + { + "classes": "never", + "blocks": "never", + "switches": "never" + } + ], + "jsdoc/require-param-description": [ + "error" + ], + "jsdoc/require-property-description": [ + "error" + ], + "jsdoc/require-returns-description": [ + "error" + ], + "jsdoc/check-alignment": [ + "error" + ], + "no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "punycode", + "message": "Package 'punycode' has to be imported with trailing slash, see warning in https://github.com/bestiejs/punycode.js#installation" + } + ], + "patterns": [ + "!punycode/" + ] + } + ], + "@typescript-eslint/consistent-type-imports": "error", + "semi": [ + "error", + "always" + ], + "quote-props": [ + "error", + "consistent-as-needed" + ], + "max-len": [ + "error", + { + "code": 150, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreComments": true, + "ignoreRegExpLiterals": true + } + ], + "no-console": [ + "error" + ], + "no-restricted-syntax": [ + "error", + { + "selector": "CallExpression:matches([callee.name='createHash'], [callee.property.name='createHash']) Literal[value='md5']", + "message": "Use the md5hash() function from the core library if you want md5" + } + ], + "@typescript-eslint/unbound-method": "error", + "jest/expect-expect": "off", + "jest/no-conditional-expect": "off", + "jest/no-done-callback": "off", + "jest/no-standalone-expect": "off", + "jest/valid-expect": "off", + "jest/valid-title": "off", + "jest/no-identical-title": "off", + "jest/no-disabled-tests": "error", + "jest/no-focused-tests": "error", + "prettier/prettier": [ + "off" + ] + }, + "overrides": [] +} diff --git a/packages/@aws-cdk/integ-runner/.gitattributes b/packages/@aws-cdk/integ-runner/.gitattributes new file mode 100644 index 000000000..c1b26c9d0 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.gitattributes @@ -0,0 +1,20 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". + +* text=auto eol=lf +/.eslintrc.js linguist-generated +/.eslintrc.json linguist-generated +/.gitattributes linguist-generated +/.gitignore linguist-generated +/.npmignore linguist-generated +/.prettierignore linguist-generated +/.prettierrc.json linguist-generated +/.projen/** linguist-generated +/.projen/deps.json linguist-generated +/.projen/files.json linguist-generated +/.projen/tasks.json linguist-generated +/jest.config.json linguist-generated +/LICENSE linguist-generated +/package.json linguist-generated +/tsconfig.dev.json linguist-generated +/tsconfig.json linguist-generated +/yarn.lock linguist-generated \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/.gitignore b/packages/@aws-cdk/integ-runner/.gitignore new file mode 100644 index 000000000..973a05824 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.gitignore @@ -0,0 +1,53 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +!/.gitattributes +!/.projen/tasks.json +!/.projen/deps.json +!/.projen/files.json +!/package.json +!/LICENSE +!/.npmignore +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json +pids +*.pid +*.seed +*.pid.lock +lib-cov +coverage +*.lcov +.nyc_output +build/Release +node_modules/ +jspm_packages/ +*.tsbuildinfo +.eslintcache +*.tgz +.yarn-integrity +.cache +!/jest.config.json +/coverage/ +!/.prettierignore +!/.prettierrc.json +!/test/ +!/tsconfig.json +!/tsconfig.dev.json +!/lib/ +/lib/**/*.js +/lib/**/*.d.ts +/lib/**/*.d.ts.map +/dist/ +!/.eslintrc.json +/dist/changelog.md +/dist/version.txt +!/.eslintrc.js +test/test-archive-follow/data/linked +!test/test-data/cdk-integ.out*/ +!**/*.snapshot/**/asset.*/*.js +!**/*.snapshot/**/asset.*/*.d.ts +!**/*.snapshot/**/asset.*/** +lib/recommended-feature-flags.json diff --git a/packages/@aws-cdk/integ-runner/.npmignore b/packages/@aws-cdk/integ-runner/.npmignore new file mode 100644 index 000000000..b68c0e7ff --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.npmignore @@ -0,0 +1,26 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +/.projen/ +/jest.config.json +/coverage/ +/.prettierignore +/.prettierrc.json +/test/ +/tsconfig.dev.json +!/lib/ +!/lib/**/*.js +!/lib/**/*.d.ts +dist +/tsconfig.json +/.github/ +/.vscode/ +/.idea/ +/.projenrc.js +tsconfig.tsbuildinfo +/.eslintrc.json +/dist/changelog.md +/dist/version.txt +.eslintrc.js +*.ts +!*.d.ts +build-tools +/.gitattributes diff --git a/packages/@aws-cdk/integ-runner/.prettierignore b/packages/@aws-cdk/integ-runner/.prettierignore new file mode 100644 index 000000000..b6999ad11 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.prettierignore @@ -0,0 +1,2 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +.eslintrc.js diff --git a/packages/@aws-cdk/integ-runner/.prettierrc.json b/packages/@aws-cdk/integ-runner/.prettierrc.json new file mode 100644 index 000000000..af318ca5f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "overrides": [] +} diff --git a/packages/@aws-cdk/integ-runner/.projen/deps.json b/packages/@aws-cdk/integ-runner/.projen/deps.json new file mode 100644 index 000000000..9580c0c1b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.projen/deps.json @@ -0,0 +1,193 @@ +{ + "dependencies": [ + { + "name": "@aws-cdk/integ-tests-alpha", + "version": "2.184.1-alpha.0", + "type": "build" + }, + { + "name": "@cdklabs/eslint-plugin", + "type": "build" + }, + { + "name": "@stylistic/eslint-plugin", + "version": "^3", + "type": "build" + }, + { + "name": "@types/fs-extra", + "type": "build" + }, + { + "name": "@types/jest", + "type": "build" + }, + { + "name": "@types/mock-fs", + "version": "^4", + "type": "build" + }, + { + "name": "@types/node", + "version": "^16", + "type": "build" + }, + { + "name": "@types/workerpool", + "version": "^6", + "type": "build" + }, + { + "name": "@types/yargs", + "type": "build" + }, + { + "name": "@typescript-eslint/eslint-plugin", + "version": "^8", + "type": "build" + }, + { + "name": "@typescript-eslint/parser", + "version": "^8", + "type": "build" + }, + { + "name": "aws-cdk-lib", + "type": "build" + }, + { + "name": "commit-and-tag-version", + "version": "^12", + "type": "build" + }, + { + "name": "constructs", + "version": "^10", + "type": "build" + }, + { + "name": "eslint-config-prettier", + "type": "build" + }, + { + "name": "eslint-import-resolver-typescript", + "type": "build" + }, + { + "name": "eslint-plugin-import", + "type": "build" + }, + { + "name": "eslint-plugin-jest", + "type": "build" + }, + { + "name": "eslint-plugin-jsdoc", + "type": "build" + }, + { + "name": "eslint-plugin-prettier", + "type": "build" + }, + { + "name": "eslint", + "version": "^9", + "type": "build" + }, + { + "name": "jest", + "type": "build" + }, + { + "name": "jest-junit", + "version": "^16", + "type": "build" + }, + { + "name": "license-checker", + "type": "build" + }, + { + "name": "mock-fs", + "version": "^5", + "type": "build" + }, + { + "name": "prettier", + "version": "^2.8", + "type": "build" + }, + { + "name": "projen", + "type": "build" + }, + { + "name": "ts-jest", + "type": "build" + }, + { + "name": "typescript", + "version": "5.6", + "type": "build" + }, + { + "name": "@aws-cdk/aws-service-spec", + "type": "runtime" + }, + { + "name": "@aws-cdk/cdk-cli-wrapper", + "type": "runtime" + }, + { + "name": "@aws-cdk/cloud-assembly-schema", + "type": "runtime" + }, + { + "name": "@aws-cdk/cloudformation-diff", + "type": "runtime" + }, + { + "name": "@aws-cdk/cx-api", + "type": "runtime" + }, + { + "name": "@aws-sdk/client-cloudformation", + "version": "^3", + "type": "runtime" + }, + { + "name": "aws-cdk", + "type": "runtime" + }, + { + "name": "cdk-assets", + "type": "runtime" + }, + { + "name": "chalk", + "version": "^4", + "type": "runtime" + }, + { + "name": "chokidar", + "version": "^3", + "type": "runtime" + }, + { + "name": "fs-extra", + "version": "^9", + "type": "runtime" + }, + { + "name": "workerpool", + "version": "^6", + "type": "runtime" + }, + { + "name": "yargs", + "version": "^16", + "type": "runtime" + } + ], + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/@aws-cdk/integ-runner/.projen/files.json b/packages/@aws-cdk/integ-runner/.projen/files.json new file mode 100644 index 000000000..493bbd87e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.projen/files.json @@ -0,0 +1,19 @@ +{ + "files": [ + ".eslintrc.js", + ".eslintrc.json", + ".gitattributes", + ".gitignore", + ".npmignore", + ".prettierignore", + ".prettierrc.json", + ".projen/deps.json", + ".projen/files.json", + ".projen/tasks.json", + "jest.config.json", + "LICENSE", + "tsconfig.dev.json", + "tsconfig.json" + ], + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/@aws-cdk/integ-runner/.projen/tasks.json b/packages/@aws-cdk/integ-runner/.projen/tasks.json new file mode 100644 index 000000000..119179fd3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/.projen/tasks.json @@ -0,0 +1,226 @@ +{ + "tasks": { + "build": { + "name": "build", + "description": "Full release build", + "steps": [ + { + "spawn": "pre-compile" + }, + { + "spawn": "compile" + }, + { + "spawn": "post-compile" + }, + { + "spawn": "test" + }, + { + "spawn": "package" + } + ] + }, + "bump": { + "name": "bump", + "description": "Bumps version based on latest git tag and generates a changelog entry", + "env": { + "OUTFILE": "package.json", + "CHANGELOG": "dist/changelog.md", + "BUMPFILE": "dist/version.txt", + "RELEASETAG": "dist/releasetag.txt", + "RELEASE_TAG_PREFIX": "@aws-cdk/integ-runner@", + "VERSIONRCOPTIONS": "{\"path\":\".\"}", + "BUMP_PACKAGE": "commit-and-tag-version@^12", + "RELEASABLE_COMMITS": "git log --no-merges --oneline $LATEST_TAG..HEAD -E --grep \"^(feat|fix){1}(\\([^()[:space:]]+\\))?(!)?:[[:blank:]]+.+\" -- ." + }, + "steps": [ + { + "spawn": "gather-versions" + }, + { + "builtin": "release/bump-version" + } + ], + "condition": "git log --oneline -1 | grep -qv \"chore(release):\"" + }, + "check-for-updates": { + "name": "check-for-updates", + "env": { + "CI": "0" + }, + "steps": [ + { + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/fs-extra,@types/jest,@types/yargs,aws-cdk-lib,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest,@aws-cdk/aws-service-spec,@aws-cdk/cx-api" + } + ] + }, + "check-licenses": { + "name": "check-licenses", + "steps": [ + { + "exec": "license-checker --summary --production --onlyAllow \"Apache-2.0;MIT;ISC\"", + "receiveArgs": true + } + ] + }, + "compile": { + "name": "compile", + "description": "Only compile", + "steps": [ + { + "exec": "tsc --build", + "receiveArgs": true + } + ] + }, + "default": { + "name": "default", + "description": "Synthesize project files", + "steps": [ + { + "exec": "cd ../../.. && npx projen default" + } + ] + }, + "eslint": { + "name": "eslint", + "description": "Runs eslint against the codebase", + "env": { + "ESLINT_USE_FLAT_CONFIG": "false" + }, + "steps": [ + { + "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ lib test build-tools", + "receiveArgs": true + } + ] + }, + "gather-versions": { + "name": "gather-versions", + "steps": [ + { + "exec": "node -e \"require(require.resolve('cdklabs-projen-project-types/lib/yarn/gather-versions.exec.js')).cliMain()\" @aws-cdk/cloud-assembly-schema=exact @aws-cdk/cdk-cli-wrapper=exact aws-cdk=exact cdk-assets=exact @aws-cdk/cloudformation-diff=exact", + "receiveArgs": true + } + ] + }, + "install": { + "name": "install", + "description": "Install project dependencies and update lockfile (non-frozen)", + "steps": [ + { + "exec": "yarn install --check-files" + } + ] + }, + "install:ci": { + "name": "install:ci", + "description": "Install project dependencies using frozen lockfile", + "steps": [ + { + "exec": "yarn install --check-files --frozen-lockfile" + } + ] + }, + "nx": { + "name": "nx", + "steps": [ + { + "exec": "nx run", + "receiveArgs": true + } + ] + }, + "package": { + "name": "package", + "description": "Creates the distribution package", + "steps": [ + { + "exec": "mkdir -p dist/js" + }, + { + "exec": "node-bundle pack --destination dist/js --external @aws-cdk/aws-service-spec:runtime --external aws-cdk:runtime --external fsevents:optional --allowed-license \"Apache-2.0\" --allowed-license \"MIT\" --allowed-license \"BSD-3-Clause\" --allowed-license \"ISC\" --allowed-license \"BSD-2-Clause\" --allowed-license \"0BSD\" --allowed-license \"MIT OR Apache-2.0\" --dont-attribute '^@aws-cdk/|^@cdklabs/|^cdk-assets$|^cdk-cli-wrapper$' --test 'bin/integ-runner --version' --entrypoint 'lib/index.js' --entrypoint 'lib/workers/extract/index.js'" + } + ] + }, + "post-compile": { + "name": "post-compile", + "description": "Runs after successful compilation", + "steps": [ + { + "exec": "node-bundle validate --fix --external @aws-cdk/aws-service-spec:runtime --external aws-cdk:runtime --external fsevents:optional --allowed-license \"Apache-2.0\" --allowed-license \"MIT\" --allowed-license \"BSD-3-Clause\" --allowed-license \"ISC\" --allowed-license \"BSD-2-Clause\" --allowed-license \"0BSD\" --allowed-license \"MIT OR Apache-2.0\" --dont-attribute '^@aws-cdk/|^@cdklabs/|^cdk-assets$|^cdk-cli-wrapper$' --test 'bin/integ-runner --version' --entrypoint 'lib/index.js' --entrypoint 'lib/workers/extract/index.js'" + } + ] + }, + "pre-compile": { + "name": "pre-compile", + "description": "Prepare the project for compilation", + "steps": [ + { + "exec": "./build-tools/generate.sh" + }, + { + "spawn": "check-licenses" + } + ] + }, + "test": { + "name": "test", + "description": "Run tests", + "steps": [ + { + "exec": "jest --passWithNoTests --updateSnapshot", + "receiveArgs": true + }, + { + "spawn": "eslint" + } + ] + }, + "test:watch": { + "name": "test:watch", + "description": "Run jest in watch mode", + "steps": [ + { + "exec": "jest --watch" + } + ] + }, + "unbump": { + "name": "unbump", + "description": "Restores version to 0.0.0", + "env": { + "OUTFILE": "package.json", + "CHANGELOG": "dist/changelog.md", + "BUMPFILE": "dist/version.txt", + "RELEASETAG": "dist/releasetag.txt", + "RELEASE_TAG_PREFIX": "@aws-cdk/integ-runner@", + "VERSIONRCOPTIONS": "{\"path\":\".\"}", + "BUMP_PACKAGE": "commit-and-tag-version@^12", + "RELEASABLE_COMMITS": "git log --no-merges --oneline $LATEST_TAG..HEAD -E --grep \"^(feat|fix){1}(\\([^()[:space:]]+\\))?(!)?:[[:blank:]]+.+\" -- ." + }, + "steps": [ + { + "builtin": "release/reset-version" + }, + { + "spawn": "gather-versions" + } + ] + }, + "watch": { + "name": "watch", + "description": "Watch & compile in the background", + "steps": [ + { + "exec": "tsc --build -w" + } + ] + } + }, + "env": { + "PATH": "$(npx -c \"node --print process.env.PATH\")" + }, + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/@aws-cdk/integ-runner/LICENSE b/packages/@aws-cdk/integ-runner/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/integ-runner/NOTICE b/packages/@aws-cdk/integ-runner/NOTICE new file mode 100644 index 000000000..cd0946c1c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/integ-runner/README.md b/packages/@aws-cdk/integ-runner/README.md new file mode 100644 index 000000000..0dd262663 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/README.md @@ -0,0 +1,322 @@ +# integ-runner + + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + +## Overview + +This tool has been created to be used initially by this repo (aws/aws-cdk). Long term the goal is +for this tool to be a general tool that can be used for running CDK integration tests. We are +publishing this tool so that it can be used by the community and we would love to receive feedback +on use cases that the tool should support, or issues that prevent the tool from being used in your +library. + +This tool is meant to be used with the [integ-tests](https://docs.aws.amazon.com/cdk/api/v2/docs/integ-tests-alpha-readme.html) library. + +## Usage + +- Run all integration tests in `test` directory + +```bash +integ-runner [ARGS] [TEST...] +``` + +This will look for all files that match the naming convention of `/integ.*.(js|ts)$/` or `/integ_*.py`. +Each of these files represents a self contained AWS CDK app, defining test cases and assertions using the [integ-tests](https://docs.aws.amazon.com/cdk/api/v2/docs/integ-tests-alpha-readme.html) library. + +By default, executing `integ-runner` will do the following for each file (app): + +1. Synth each integration test to create a new snapshot in memory +2. Compare the snapshot to the previous version (i.e. files in `*.snapshot/**`), and fail on any differences.\ + For new tests this will always fail. + +To accept a snapshot update, the integreation test has to be deployed and assertions have to pass.\ +Execute the runner again, this time with `integ-runner --update-on-fail` and the following will happen for each file: + +1. Deploy the previous snapshot +2. Deploy the new version as a Stack update and run assertions +3. If successful, update the snapshots + +All snapshot files (i.e. `*.snapshot/**`) must be checked-in to version control. +If not, changes cannot be compared across systems and the [update workflow](#update-workflow) cannot be used. + +### Options + +- `--update-on-failed` (default=`false`) + Rerun integration tests if snapshot fails +- `--clean` (default=`true`) + Destroy stacks after deploy (use `--no-clean` for debugging) +- `--verbose` (default=`false`) + verbose logging, including integration test metrics + (specify multiple times to increase verbosity) +- `--parallel-regions` (default=`us-east-1`,`us-east-2`, `us-west-2`) + List of regions to run tests in. If this is provided then all tests will + be run in parallel across these regions +- `--directory` (default=`test`) + Search for integration tests recursively from this starting directory +- `--force` (default=`false`) + Rerun integration test even if the test passes +- `--profiles` + List of AWS Profiles to use when running tests in parallel +- `--exclude` (default=`false`) + If this is set to `true` then the list of tests provided will be excluded +- `--from-file` + Read the list of tests from this file +- `--disable-update-workflow` (default=`false`) + 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. + +- `--watch` + Run a single integration test in watch mode. In watch mode the integ-runner + will not save any snapshots. + + 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 typescript --language python`). 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\..*(? (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** ansi-styles@4.3.0 - https://www.npmjs.com/package/ansi-styles/v/4.3.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** anymatch@3.1.3 - https://www.npmjs.com/package/anymatch/v/3.1.3 | ISC +The ISC License + +Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com) + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** astral-regex@2.0.0 - https://www.npmjs.com/package/astral-regex/v/2.0.0 | MIT +MIT License + +Copyright (c) Kevin Mårtensson (github.com/kevva) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** at-least-node@1.0.0 - https://www.npmjs.com/package/at-least-node/v/1.0.0 | ISC +The ISC License +Copyright (c) 2020 Ryan Zimmerman + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** binary-extensions@2.3.0 - https://www.npmjs.com/package/binary-extensions/v/2.3.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) +Copyright (c) Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** braces@3.0.3 - https://www.npmjs.com/package/braces/v/3.0.3 | MIT +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** chalk@4.1.2 - https://www.npmjs.com/package/chalk/v/4.1.2 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** chokidar@3.6.0 - https://www.npmjs.com/package/chokidar/v/3.6.0 | MIT +The MIT License (MIT) + +Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** cliui@7.0.4 - https://www.npmjs.com/package/cliui/v/7.0.4 | ISC +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** color-convert@2.0.1 - https://www.npmjs.com/package/color-convert/v/2.0.1 | MIT +Copyright (c) 2011-2016 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +---------------- + +** color-name@1.1.4 - https://www.npmjs.com/package/color-name/v/1.1.4 | MIT +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------- + +** diff@7.0.0 - https://www.npmjs.com/package/diff/v/7.0.0 | BSD-3-Clause +BSD 3-Clause License + +Copyright (c) 2009-2015, Kevin Decker +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** emoji-regex@8.0.0 - https://www.npmjs.com/package/emoji-regex/v/8.0.0 | MIT +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** escalade@3.2.0 - https://www.npmjs.com/package/escalade/v/3.2.0 | MIT +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** fast-deep-equal@3.1.3 - https://www.npmjs.com/package/fast-deep-equal/v/3.1.3 | MIT +MIT License + +Copyright (c) 2017 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** fill-range@7.1.1 - https://www.npmjs.com/package/fill-range/v/7.1.1 | MIT +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** fs-extra@9.1.0 - https://www.npmjs.com/package/fs-extra/v/9.1.0 | MIT +(The MIT License) + +Copyright (c) 2011-2017 JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** get-caller-file@2.0.5 - https://www.npmjs.com/package/get-caller-file/v/2.0.5 | ISC + +---------------- + +** glob-parent@5.1.2 - https://www.npmjs.com/package/glob-parent/v/5.1.2 | ISC +The ISC License + +Copyright (c) 2015, 2019 Elan Shanker + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** graceful-fs@4.2.11 - https://www.npmjs.com/package/graceful-fs/v/4.2.11 | ISC +The ISC License + +Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** has-flag@4.0.0 - https://www.npmjs.com/package/has-flag/v/4.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** is-binary-path@2.1.0 - https://www.npmjs.com/package/is-binary-path/v/2.1.0 | MIT +MIT License + +Copyright (c) 2019 Sindre Sorhus (https://sindresorhus.com), Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** is-extglob@2.1.1 - https://www.npmjs.com/package/is-extglob/v/2.1.1 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2016, Jon Schlinkert + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** is-fullwidth-code-point@3.0.0 - https://www.npmjs.com/package/is-fullwidth-code-point/v/3.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** is-glob@4.0.3 - https://www.npmjs.com/package/is-glob/v/4.0.3 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** is-number@7.0.0 - https://www.npmjs.com/package/is-number/v/7.0.0 | MIT +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** jsonfile@6.1.0 - https://www.npmjs.com/package/jsonfile/v/6.1.0 | MIT +(The MIT License) + +Copyright (c) 2012-2015, JP Richardson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** jsonschema@1.4.1 - https://www.npmjs.com/package/jsonschema/v/1.4.1 | MIT +jsonschema is licensed under MIT license. + +Copyright (C) 2012-2015 Tom de Grunt + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** lodash.truncate@4.4.2 - https://www.npmjs.com/package/lodash.truncate/v/4.4.2 | MIT +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +---------------- + +** normalize-path@3.0.0 - https://www.npmjs.com/package/normalize-path/v/3.0.0 | MIT +The MIT License (MIT) + +Copyright (c) 2014-2018, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** picomatch@2.3.1 - https://www.npmjs.com/package/picomatch/v/2.3.1 | MIT +The MIT License (MIT) + +Copyright (c) 2017-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** readdirp@3.6.0 - https://www.npmjs.com/package/readdirp/v/3.6.0 | MIT +MIT License + +Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +---------------- + +** require-directory@2.1.1 - https://www.npmjs.com/package/require-directory/v/2.1.1 | MIT +The MIT License (MIT) + +Copyright (c) 2011 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** semver@7.7.1 - https://www.npmjs.com/package/semver/v/7.7.1 | ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** slice-ansi@4.0.0 - https://www.npmjs.com/package/slice-ansi/v/4.0.0 | MIT +MIT License + +Copyright (c) DC +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** string-width@4.2.3 - https://www.npmjs.com/package/string-width/v/4.2.3 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** strip-ansi@6.0.1 - https://www.npmjs.com/package/strip-ansi/v/6.0.1 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** supports-color@7.2.0 - https://www.npmjs.com/package/supports-color/v/7.2.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** table@6.9.0 - https://www.npmjs.com/package/table/v/6.9.0 | BSD-3-Clause +Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------- + +** to-regex-range@5.0.1 - https://www.npmjs.com/package/to-regex-range/v/5.0.1 | MIT +The MIT License (MIT) + +Copyright (c) 2015-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- + +** universalify@2.0.1 - https://www.npmjs.com/package/universalify/v/2.0.1 | MIT +(The MIT License) + +Copyright (c) 2017, Ryan Zimmerman + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** workerpool@6.5.1 - https://www.npmjs.com/package/workerpool/v/6.5.1 | Apache-2.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) 2014-2023 Jos de Jong wjosdejong@gmail.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---------------- + +** wrap-ansi@7.0.0 - https://www.npmjs.com/package/wrap-ansi/v/7.0.0 | MIT +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +---------------- + +** y18n@5.0.8 - https://www.npmjs.com/package/y18n/v/5.0.8 | ISC +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + +---------------- + +** yargs-parser@20.2.9 - https://www.npmjs.com/package/yargs-parser/v/20.2.9 | ISC +Copyright (c) 2016, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +---------------- + +** yargs@16.2.0 - https://www.npmjs.com/package/yargs/v/16.2.0 | MIT +MIT License + +Copyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +---------------- diff --git a/packages/@aws-cdk/integ-runner/bin/integ-runner b/packages/@aws-cdk/integ-runner/bin/integ-runner new file mode 100755 index 000000000..171249b23 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/bin/integ-runner @@ -0,0 +1,4 @@ +#!/usr/bin/env node +const { cli } = require('../lib'); +cli(); + diff --git a/packages/@aws-cdk/integ-runner/build-tools/generate.sh b/packages/@aws-cdk/integ-runner/build-tools/generate.sh new file mode 100755 index 000000000..36839187b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/build-tools/generate.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail + +# Copy the recommended-feature-flags.json file out from aws-cdk-lib. +path=$(node -p 'require.resolve("aws-cdk-lib/recommended-feature-flags.json")') +cp $path lib/recommended-feature-flags.json \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/jest.config.json b/packages/@aws-cdk/integ-runner/jest.config.json new file mode 100644 index 000000000..cb081731d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/jest.config.json @@ -0,0 +1,67 @@ +{ + "coverageProvider": "v8", + "moduleFileExtensions": [ + "ts", + "js" + ], + "maxWorkers": "80%", + "testEnvironment": "node", + "coverageThreshold": { + "global": { + "statements": 80, + "branches": 79, + "functions": 80, + "lines": 80 + } + }, + "collectCoverage": true, + "coverageReporters": [ + "text-summary", + "cobertura", + [ + "html", + { + "subdir": "html-report" + } + ] + ], + "testMatch": [ + "/test/**/?(*.)+(test).ts", + "/@(lib|test)/**/*(*.)@(spec|test).ts?(x)", + "/@(lib|test)/**/__tests__/**/*.ts?(x)" + ], + "coveragePathIgnorePatterns": [ + "\\.generated\\.[jt]s$", + "/test/", + ".warnings.jsii.js$", + "/node_modules/" + ], + "reporters": [ + "default", + [ + "jest-junit", + { + "suiteName": "jest tests", + "outputDirectory": "coverage" + } + ] + ], + "randomize": true, + "clearMocks": true, + "coverageDirectory": "coverage", + "testPathIgnorePatterns": [ + "/node_modules/" + ], + "watchPathIgnorePatterns": [ + "/node_modules/" + ], + "transform": { + "^.+\\.[t]sx?$": [ + "ts-jest", + { + "tsconfig": "tsconfig.dev.json" + } + ] + }, + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/@aws-cdk/integ-runner/lib/cli.ts b/packages/@aws-cdk/integ-runner/lib/cli.ts new file mode 100644 index 000000000..a7731082e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/cli.ts @@ -0,0 +1,302 @@ +// Exercise all integ stacks and if they deploy, update the expected synth files +import * as fs from 'fs'; +import * as path from 'path'; +import * as chalk from 'chalk'; +import * as workerpool from 'workerpool'; +import * as logger from './logger'; +import type { IntegTest, IntegTestInfo } from './runner/integration-tests'; +import { IntegrationTests } from './runner/integration-tests'; +import type { IntegRunnerMetrics, IntegTestWorkerConfig, DestructiveChange } from './workers'; +import { runSnapshotTests, runIntegrationTests } from './workers'; +import { watchIntegrationTest } from './workers/integ-watch-worker'; + +// https://github.com/yargs/yargs/issues/1929 +// https://github.com/evanw/esbuild/issues/1492 +// eslint-disable-next-line @typescript-eslint/no-require-imports +const yargs = require('yargs'); + +export function parseCliArgs(args: string[] = []) { + const argv = yargs + .usage('Usage: integ-runner [TEST...]') + .option('config', { + config: true, + configParser: configFromFile, + default: 'integ.config.json', + desc: 'Load options from a JSON config file. Options provided as CLI arguments take precedent.', + }) + .option('watch', { type: 'boolean', default: false, desc: 'Perform integ tests in watch mode' }) + .option('list', { type: 'boolean', default: false, desc: 'List tests instead of running them' }) + .option('clean', { type: 'boolean', default: true, desc: 'Skips stack clean up after test is completed (use --no-clean to negate)' }) + .option('verbose', { type: 'boolean', default: false, alias: 'v', count: true, desc: 'Verbose logs and metrics on integration tests durations (specify multiple times to increase verbosity)' }) + .option('dry-run', { type: 'boolean', default: false, desc: 'do not actually deploy the stack. just update the snapshot (not recommended!)' }) + .option('update-on-failed', { type: 'boolean', default: false, desc: 'rerun integration tests and update snapshots for failed tests.' }) + .option('force', { type: 'boolean', default: false, desc: 'Rerun all integration tests even if tests are passing' }) + .option('parallel-regions', { type: 'array', desc: 'Tests are run in parallel across these regions. To prevent tests from running in parallel, provide only a single region', default: [] }) + .options('directory', { type: 'string', default: 'test', desc: 'starting directory to discover integration tests. Tests will be discovered recursively from this directory' }) + .options('profiles', { type: 'array', desc: 'list of AWS profiles to use. Tests will be run in parallel across each profile+regions', default: [] }) + .options('max-workers', { type: 'number', desc: 'The max number of workerpool workers to use when running integration tests in parallel', default: 16 }) + .options('exclude', { type: 'boolean', desc: 'Run all tests in the directory, except the specified TESTs', default: false }) + .options('from-file', { type: 'string', desc: 'Read TEST names from a file (one TEST per line)' }) + .option('inspect-failures', { type: 'boolean', desc: 'Keep the integ test cloud assembly if a failure occurs for inspection', default: false }) + .option('disable-update-workflow', { type: 'boolean', default: false, desc: 'If this is "true" then the stack update workflow will be disabled' }) + .option('language', { + alias: 'l', + default: ['javascript', 'typescript', 'python', 'go'], + choices: ['javascript', 'typescript', 'python', 'go'], + type: 'array', + nargs: 1, + desc: 'Use these presets to run integration tests for the selected languages', + }) + .option('app', { type: 'string', default: undefined, desc: '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}".' }) + .option('test-regex', { type: 'array', desc: 'Detect integration test files matching this JavaScript regex pattern. If used multiple times, all files matching any one of the patterns are detected.', default: [] }) + .strict() + .parse(args); + + const tests: string[] = argv._; + const parallelRegions = arrayFromYargs(argv['parallel-regions']); + const testRegions: string[] = parallelRegions ?? ['us-east-1', 'us-east-2', 'us-west-2']; + const profiles = arrayFromYargs(argv.profiles); + const fromFile: string | undefined = argv['from-file']; + const maxWorkers: number = argv['max-workers']; + const verbosity: number = argv.verbose; + const verbose: boolean = verbosity >= 1; + + const numTests = testRegions.length * (profiles ?? [1]).length; + if (maxWorkers < numTests) { + logger.warning('You are attempting to run %s tests in parallel, but only have %s workers. Not all of your profiles+regions will be utilized', numTests, maxWorkers); + } + + if (tests.length > 0 && fromFile) { + throw new Error('A list of tests cannot be provided if "--from-file" is provided'); + } + const requestedTests = fromFile + ? (fs.readFileSync(fromFile, { encoding: 'utf8' })).split('\n').filter(x => x) + : (tests.length > 0 ? tests : undefined); // 'undefined' means no request + + return { + tests: requestedTests, + app: argv.app as (string | undefined), + testRegex: arrayFromYargs(argv['test-regex']), + testRegions, + originalRegions: parallelRegions, + profiles, + runUpdateOnFailed: (argv['update-on-failed'] ?? false) as boolean, + fromFile, + exclude: argv.exclude as boolean, + maxWorkers, + list: argv.list as boolean, + directory: argv.directory as string, + inspectFailures: argv['inspect-failures'] as boolean, + verbosity, + verbose, + clean: argv.clean as boolean, + force: argv.force as boolean, + dryRun: argv['dry-run'] as boolean, + disableUpdateWorkflow: argv['disable-update-workflow'] as boolean, + language: arrayFromYargs(argv.language), + watch: argv.watch as boolean, + }; +} + +export async function main(args: string[]) { + const options = parseCliArgs(args); + + const testsFromArgs = await new IntegrationTests(path.resolve(options.directory)).fromCliOptions(options); + + // List only prints the discovered tests + if (options.list) { + process.stdout.write(testsFromArgs.map(t => t.discoveryRelativeFileName).join('\n') + '\n'); + return; + } + + const pool = workerpool.pool(path.join(__dirname, '..', 'lib', 'workers', 'extract', 'index.js'), { + maxWorkers: options.watch ? 1 : options.maxWorkers, + }); + + const testsToRun: IntegTestWorkerConfig[] = []; + let destructiveChanges: boolean = false; + let failedSnapshots: IntegTestWorkerConfig[] = []; + let testsSucceeded = false; + validateWatchArgs({ + ...options, + testRegions: options.originalRegions, + tests: testsFromArgs, + }); + + try { + if (!options.watch) { + // always run snapshot tests, but if '--force' is passed then + // run integration tests on all failed tests, not just those that + // failed snapshot tests + failedSnapshots = await runSnapshotTests(pool, testsFromArgs, { + retain: options.inspectFailures, + verbose: options.verbose, + }); + for (const failure of failedSnapshots) { + logger.warning(`Failed: ${failure.fileName}`); + if (failure.destructiveChanges && failure.destructiveChanges.length > 0) { + printDestructiveChanges(failure.destructiveChanges); + destructiveChanges = true; + } + } + if (!options.force) { + testsToRun.push(...failedSnapshots); + } else { + // if any of the test failed snapshot tests, keep those results + // and merge with the rest of the tests from args + testsToRun.push(...mergeTests(testsFromArgs.map(t => t.info), failedSnapshots)); + } + } else { + testsToRun.push(...testsFromArgs.map(t => t.info)); + } + + // run integration tests if `--update-on-failed` OR `--force` is used + if (options.runUpdateOnFailed || options.force) { + const { success, metrics } = await runIntegrationTests({ + pool, + tests: testsToRun, + regions: options.testRegions, + profiles: options.profiles, + clean: options.clean, + dryRun: options.dryRun, + verbosity: options.verbosity, + updateWorkflow: !options.disableUpdateWorkflow, + watch: options.watch, + }); + testsSucceeded = success; + + if (options.clean === false) { + logger.warning('Not cleaning up stacks since "--no-clean" was used'); + } + + if (Boolean(options.verbose)) { + printMetrics(metrics); + } + + if (!success) { + throw new Error('Some integration tests failed!'); + } + } else if (options.watch) { + await watchIntegrationTest(pool, { + watch: true, + verbosity: options.verbosity, + ...testsToRun[0], + profile: options.profiles ? options.profiles[0] : undefined, + region: options.testRegions[0], + }); + } + } finally { + void pool.terminate(); + } + + if (destructiveChanges) { + throw new Error('Some changes were destructive!'); + } + if (failedSnapshots.length > 0) { + let message = ''; + if (!options.runUpdateOnFailed) { + message = 'To re-run failed tests run: integ-runner --update-on-failed'; + } + if (!testsSucceeded) { + throw new Error(`Some tests failed!\n${message}`); + } + } +} + +function validateWatchArgs(args: { + tests: IntegTest[]; + testRegions?: string[]; + profiles?: string[]; + maxWorkers: number; + force: boolean; + dryRun: boolean; + disableUpdateWorkflow: boolean; + runUpdateOnFailed: boolean; + watch: boolean; +}) { + if (args.watch) { + if ( + (args.testRegions && args.testRegions.length > 1) + || (args.profiles && args.profiles.length > 1) + || args.tests.length > 1) { + throw new Error('Running with watch only supports a single test. Only provide a single option'+ + 'to `--profiles` `--parallel-regions` `--max-workers'); + } + + if (args.runUpdateOnFailed || args.disableUpdateWorkflow || args.force || args.dryRun) { + logger.warning('args `--update-on-failed`, `--disable-update-workflow`, `--force`, `--dry-run` have no effect when running with `--watch`'); + } + } +} + +function printDestructiveChanges(changes: DestructiveChange[]): void { + if (changes.length > 0) { + logger.warning('!!! This test contains %s !!!', chalk.bold('destructive changes')); + changes.forEach(change => { + logger.warning(' Stack: %s - Resource: %s - Impact: %s', change.stackName, change.logicalId, change.impact); + }); + logger.warning('!!! If these destructive changes are necessary, please indicate this on the PR !!!'); + } +} + +function printMetrics(metrics: IntegRunnerMetrics[]): void { + logger.highlight(' --- Integration test metrics ---'); + const sortedMetrics = metrics.sort((a, b) => a.duration - b.duration); + sortedMetrics.forEach(metric => { + logger.print('Profile %s + Region %s total time: %s', metric.profile, metric.region, metric.duration); + const sortedTests = Object.entries(metric.tests).sort((a, b) => a[1] - b[1]); + sortedTests.forEach(test => logger.print(' %s: %s', test[0], test[1])); + }); +} + +/** + * Translate a Yargs input array to something that makes more sense in a programming language + * model (telling the difference between absence and an empty array) + * + * - An empty array is the default case, meaning the user didn't pass any arguments. We return + * undefined. + * - If the user passed a single empty string, they did something like `--array=`, which we'll + * take to mean they passed an empty array. + */ +function arrayFromYargs(xs: string[]): string[] | undefined { + if (xs.length === 0) { + return undefined; + } + return xs.filter(x => x !== ''); +} + +/** + * Merge the tests we received from command line arguments with + * tests that failed snapshot tests. The failed snapshot tests have additional + * information that we want to keep so this should override any test from args + */ +function mergeTests(testFromArgs: IntegTestInfo[], failedSnapshotTests: IntegTestWorkerConfig[]): IntegTestWorkerConfig[] { + const failedTestNames = new Set(failedSnapshotTests.map(test => test.fileName)); + const final: IntegTestWorkerConfig[] = failedSnapshotTests; + final.push(...testFromArgs.filter(test => !failedTestNames.has(test.fileName))); + return final; +} + +export function cli(args: string[] = process.argv.slice(2)) { + main(args).then().catch(err => { + logger.error(err); + process.exitCode = 1; + }); +} + +/** + * Read CLI options from a config file if provided. + * + * @returns parsed CLI config options + */ +function configFromFile(fileName?: string): Record { + if (!fileName) { + return {}; + } + + try { + return JSON.parse(fs.readFileSync(fileName, { encoding: 'utf-8' })); + } catch { + return {}; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/index.ts b/packages/@aws-cdk/integ-runner/lib/index.ts new file mode 100644 index 000000000..e8523067d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/index.ts @@ -0,0 +1 @@ +export { cli } from './cli'; diff --git a/packages/@aws-cdk/integ-runner/lib/logger.ts b/packages/@aws-cdk/integ-runner/lib/logger.ts new file mode 100644 index 000000000..b656feed3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/logger.ts @@ -0,0 +1,20 @@ +import type { Writable } from 'stream'; +import * as util from 'util'; +import * as chalk from 'chalk'; + +type StyleFn = (str: string) => string; +const { stderr } = process; + +const logger = (stream: Writable, styles?: StyleFn[]) => (fmt: string, ...args: any[]) => { + let str = util.format(fmt, ...args); + if (styles && styles.length) { + str = styles.reduce((a, style) => style(a), str); + } + stream.write(str + '\n'); +}; + +export const print = logger(stderr); +export const error = logger(stderr, [chalk.red]); +export const warning = logger(stderr, [chalk.yellow]); +export const success = logger(stderr, [chalk.green]); +export const highlight = logger(stderr, [chalk.bold]); diff --git a/packages/@aws-cdk/integ-runner/lib/recommended-feature-flags.json b/packages/@aws-cdk/integ-runner/lib/recommended-feature-flags.json new file mode 100644 index 000000000..6b0c08c27 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/recommended-feature-flags.json @@ -0,0 +1,70 @@ +{ + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, + "@aws-cdk/aws-efs:denyAnonymousAccess": true, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, + "@aws-cdk/aws-eks:nodegroupNameAttribute": true, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": true, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true, + "@aws-cdk/core:enableAdditionalMetadataCollection": true, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": true, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": true +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/lib/runner/index.ts b/packages/@aws-cdk/integ-runner/lib/runner/index.ts new file mode 100644 index 000000000..6445fb09b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/index.ts @@ -0,0 +1,5 @@ +export * from './runner-base'; +export * from './integ-test-suite'; +export * from './integ-test-runner'; +export * from './snapshot-test-runner'; +export * from './integration-tests'; diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integ-test-runner.ts b/packages/@aws-cdk/integ-runner/lib/runner/integ-test-runner.ts new file mode 100644 index 000000000..843e538eb --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/integ-test-runner.ts @@ -0,0 +1,587 @@ +import * as path from 'path'; +import type { DeployOptions, DestroyOptions } from '@aws-cdk/cdk-cli-wrapper'; +import { HotswapMode, StackActivityProgress } from '@aws-cdk/cdk-cli-wrapper'; +import { RequireApproval } from '@aws-cdk/cloud-assembly-schema'; +import * as chokidar from 'chokidar'; +import * as fs from 'fs-extra'; +import * as workerpool from 'workerpool'; +import type { IntegRunnerOptions } from './runner-base'; +import { IntegRunner, DEFAULT_SYNTH_OPTIONS } from './runner-base'; +import * as logger from '../logger'; +import { chunks, exec } from '../utils'; +import type { DestructiveChange, AssertionResults, AssertionResult } from '../workers/common'; +import { DiagnosticReason, formatAssertionResults } from '../workers/common'; + +export interface CommonOptions { + /** + * The name of the test case + */ + readonly testCaseName: string; + + /** + * The level of verbosity for logging. + * + * @default 0 + */ + readonly verbosity?: number; +} + +export interface WatchOptions extends CommonOptions { + +} + +/** + * Options for the integration test runner + */ +export interface RunOptions extends CommonOptions { + /** + * Whether or not to run `cdk destroy` and cleanup the + * integration test stacks. + * + * Set this to false if you need to perform any validation + * or troubleshooting after deployment. + * + * @default true + */ + readonly clean?: boolean; + + /** + * If set to true, the integration test will not deploy + * anything and will simply update the snapshot. + * + * You should NOT use this method since you are essentially + * bypassing the integration test. + * + * @default false + */ + readonly dryRun?: boolean; + + /** + * If this is set to false then the stack update workflow will + * not be run + * + * The update workflow exists to check for cases where a change would cause + * a failure to an existing stack, but not for a newly created stack. + * + * @default true + */ + readonly updateWorkflow?: boolean; +} + +/** + * An integration test runner that orchestrates executing + * integration tests + */ +export class IntegTestRunner extends IntegRunner { + constructor(options: IntegRunnerOptions, destructiveChanges?: DestructiveChange[]) { + super(options); + this._destructiveChanges = destructiveChanges; + + // We don't want new tests written in the legacy mode. + // If there is no existing snapshot _and_ this is a legacy + // test then point the user to the new `IntegTest` construct + if (!this.hasSnapshot() && this.isLegacyTest) { + throw new Error(`${this.testName} is a new test. Please use the IntegTest construct ` + + 'to configure the test\n' + + 'https://github.com/aws/aws-cdk/tree/main/packages/%40aws-cdk/integ-tests-alpha', + ); + } + } + + public createCdkContextJson(): void { + if (!fs.existsSync(this.cdkContextPath)) { + fs.writeFileSync(this.cdkContextPath, JSON.stringify({ + watch: { }, + }, undefined, 2)); + } + } + + /** + * When running integration tests with the update path workflow + * it is important that the snapshot that is deployed is the current snapshot + * from the upstream branch. In order to guarantee that, first checkout the latest + * (to the user) snapshot from upstream + * + * It is not straightforward to figure out what branch the current + * working branch was created from. This is a best effort attempt to do so. + * This assumes that there is an 'origin'. `git remote show origin` returns a list of + * all branches and we then search for one that starts with `HEAD branch: ` + */ + private checkoutSnapshot(): void { + const cwd = this.directory; + + // https://git-scm.com/docs/git-merge-base + let baseBranch: string | undefined = undefined; + // try to find the base branch that the working branch was created from + try { + const origin: string = exec(['git', 'remote', 'show', 'origin'], { + cwd, + }); + const originLines = origin.split('\n'); + for (const line of originLines) { + if (line.trim().startsWith('HEAD branch: ')) { + baseBranch = line.trim().split('HEAD branch: ')[1]; + } + } + } catch (e) { + logger.warning('%s\n%s', + 'Could not determine git origin branch.', + `You need to manually checkout the snapshot directory ${this.snapshotDir}` + + 'from the merge-base (https://git-scm.com/docs/git-merge-base)', + ); + logger.warning('error: %s', e); + } + + // if we found the base branch then get the merge-base (most recent common commit) + // and checkout the snapshot using that commit + if (baseBranch) { + const relativeSnapshotDir = path.relative(this.directory, this.snapshotDir); + + try { + const base = exec(['git', 'merge-base', 'HEAD', baseBranch], { + cwd, + }); + exec(['git', 'checkout', base, '--', relativeSnapshotDir], { + cwd, + }); + } catch (e) { + logger.warning('%s\n%s', + `Could not checkout snapshot directory '${this.snapshotDir}'. Please verify the following command completes correctly:`, + `git checkout $(git merge-base HEAD ${baseBranch}) -- ${relativeSnapshotDir}`, + '', + ); + logger.warning('error: %s', e); + } + } + } + + /** + * Runs cdk deploy --watch for an integration test + * + * This is meant to be run on a single test and will not create a snapshot + */ + public async watchIntegTest(options: WatchOptions): Promise { + const actualTestCase = this.actualTestSuite.testSuite[options.testCaseName]; + if (!actualTestCase) { + throw new Error(`Did not find test case name '${options.testCaseName}' in '${Object.keys(this.actualTestSuite.testSuite)}'`); + } + const enableForVerbosityLevel = (needed = 1) => { + const verbosity = options.verbosity ?? 0; + return (verbosity >= needed) ? true : undefined; + }; + try { + await this.watch( + { + ...this.defaultArgs, + progress: StackActivityProgress.BAR, + hotswap: HotswapMode.FALL_BACK, + deploymentMethod: 'direct', + profile: this.profile, + requireApproval: RequireApproval.NEVER, + traceLogs: enableForVerbosityLevel(2) ?? false, + verbose: enableForVerbosityLevel(3), + debug: enableForVerbosityLevel(4), + watch: true, + }, + options.testCaseName, + options.verbosity ?? 0, + ); + } catch (e) { + throw e; + } + } + + /** + * Orchestrates running integration tests. Currently this includes + * + * 1. (if update workflow is enabled) Deploying the snapshot test stacks + * 2. Deploying the integration test stacks + * 2. Saving the snapshot (if successful) + * 3. Destroying the integration test stacks (if clean=false) + * + * The update workflow exists to check for cases where a change would cause + * a failure to an existing stack, but not for a newly created stack. + */ + public runIntegTestCase(options: RunOptions): AssertionResults | undefined { + let assertionResults: AssertionResults | undefined; + const actualTestCase = this.actualTestSuite.testSuite[options.testCaseName]; + if (!actualTestCase) { + throw new Error(`Did not find test case name '${options.testCaseName}' in '${Object.keys(this.actualTestSuite.testSuite)}'`); + } + const clean = options.clean ?? true; + const updateWorkflowEnabled = (options.updateWorkflow ?? true) + && (actualTestCase.stackUpdateWorkflow ?? true); + const enableForVerbosityLevel = (needed = 1) => { + const verbosity = options.verbosity ?? 0; + return (verbosity >= needed) ? true : undefined; + }; + + try { + if (!options.dryRun && (actualTestCase.cdkCommandOptions?.deploy?.enabled ?? true)) { + assertionResults = this.deploy( + { + ...this.defaultArgs, + profile: this.profile, + requireApproval: RequireApproval.NEVER, + verbose: enableForVerbosityLevel(3), + debug: enableForVerbosityLevel(4), + }, + updateWorkflowEnabled, + options.testCaseName, + ); + } else { + const env: Record = { + ...DEFAULT_SYNTH_OPTIONS.env, + CDK_CONTEXT_JSON: JSON.stringify(this.getContext({ + ...this.actualTestSuite.enableLookups ? DEFAULT_SYNTH_OPTIONS.context : {}, + })), + }; + this.cdk.synthFast({ + execCmd: this.cdkApp.split(' '), + env, + output: path.relative(this.directory, this.cdkOutDir), + }); + } + // only create the snapshot if there are no failed assertion results + // (i.e. no failures) + if (!assertionResults || !Object.values(assertionResults).some(result => result.status === 'fail')) { + this.createSnapshot(); + } + } catch (e) { + throw e; + } finally { + if (!options.dryRun) { + if (clean && (actualTestCase.cdkCommandOptions?.destroy?.enabled ?? true)) { + this.destroy(options.testCaseName, { + ...this.defaultArgs, + profile: this.profile, + all: true, + force: true, + app: this.cdkApp, + output: path.relative(this.directory, this.cdkOutDir), + ...actualTestCase.cdkCommandOptions?.destroy?.args, + context: this.getContext(actualTestCase.cdkCommandOptions?.destroy?.args?.context), + verbose: enableForVerbosityLevel(3), + debug: enableForVerbosityLevel(4), + }); + } + } + this.cleanup(); + } + return assertionResults; + } + + /** + * Perform a integ test case stack destruction + */ + private destroy(testCaseName: string, destroyArgs: DestroyOptions) { + const actualTestCase = this.actualTestSuite.testSuite[testCaseName]; + try { + if (actualTestCase.hooks?.preDestroy) { + actualTestCase.hooks.preDestroy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + this.cdk.destroy({ + ...destroyArgs, + }); + + if (actualTestCase.hooks?.postDestroy) { + actualTestCase.hooks.postDestroy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + } catch (e) { + this.parseError(e, + actualTestCase.cdkCommandOptions?.destroy?.expectError ?? false, + actualTestCase.cdkCommandOptions?.destroy?.expectedMessage, + ); + } + } + + private async watch(watchArgs: DeployOptions, testCaseName: string, verbosity: number): Promise { + const actualTestCase = this.actualTestSuite.testSuite[testCaseName]; + if (actualTestCase.hooks?.preDeploy) { + actualTestCase.hooks.preDeploy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + const deployArgs = { + ...watchArgs, + lookups: this.actualTestSuite.enableLookups, + stacks: [ + ...actualTestCase.stacks, + ...actualTestCase.assertionStack ? [actualTestCase.assertionStack] : [], + ], + output: path.relative(this.directory, this.cdkOutDir), + outputsFile: path.relative(this.directory, path.join(this.cdkOutDir, 'assertion-results.json')), + ...actualTestCase?.cdkCommandOptions?.deploy?.args, + context: { + ...this.getContext(actualTestCase?.cdkCommandOptions?.deploy?.args?.context), + }, + app: this.cdkApp, + }; + const destroyMessage = { + additionalMessages: [ + 'After you are done you must manually destroy the deployed stacks', + ` ${[ + ...process.env.AWS_REGION ? [`AWS_REGION=${process.env.AWS_REGION}`] : [], + 'cdk destroy', + `-a '${this.cdkApp}'`, + deployArgs.stacks.join(' '), + `--profile ${deployArgs.profile}`, + ].join(' ')}`, + ], + }; + workerpool.workerEmit(destroyMessage); + if (watchArgs.verbose) { + // if `-vvv` (or above) is used then print out the command that was used + // this allows users to manually run the command + workerpool.workerEmit({ + additionalMessages: [ + 'Repro:', + ` ${[ + 'cdk synth', + `-a '${this.cdkApp}'`, + `-o '${this.cdkOutDir}'`, + ...Object.entries(this.getContext()).flatMap(([k, v]) => typeof v !== 'object' ? [`-c '${k}=${v}'`] : []), + deployArgs.stacks.join(' '), + `--outputs-file ${deployArgs.outputsFile}`, + `--profile ${deployArgs.profile}`, + '--hotswap-fallback', + ].join(' ')}`, + ], + }); + } + + const assertionResults = path.join(this.cdkOutDir, 'assertion-results.json'); + const watcher = chokidar.watch([this.cdkOutDir], { + cwd: this.directory, + }); + watcher.on('all', (event: 'add' | 'change', file: string) => { + // we only care about changes to the `assertion-results.json` file. If there + // are assertions then this will change on every deployment + if (assertionResults.endsWith(file) && (event === 'add' || event === 'change')) { + const start = Date.now(); + if (actualTestCase.hooks?.postDeploy) { + actualTestCase.hooks.postDeploy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + + if (actualTestCase.assertionStack && actualTestCase.assertionStackName) { + const res = this.processAssertionResults( + assertionResults, + actualTestCase.assertionStackName, + actualTestCase.assertionStack, + ); + if (res && Object.values(res).some(r => r.status === 'fail')) { + workerpool.workerEmit({ + reason: DiagnosticReason.ASSERTION_FAILED, + testName: `${testCaseName} (${watchArgs.profile}`, + message: formatAssertionResults(res), + duration: (Date.now() - start) / 1000, + }); + } else { + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_SUCCESS, + testName: `${testCaseName}`, + message: res ? formatAssertionResults(res) : 'NO ASSERTIONS', + duration: (Date.now() - start) / 1000, + }); + } + // emit the destroy message after every run + // so that it's visible to the user + workerpool.workerEmit(destroyMessage); + } + } + }); + await new Promise(resolve => { + watcher.on('ready', async () => { + resolve({}); + }); + }); + + const child = this.cdk.watch(deployArgs); + // if `-v` (or above) is passed then stream the logs + child.stdout?.on('data', (message) => { + if (verbosity > 0) { + process.stdout.write(message); + } + }); + child.stderr?.on('data', (message) => { + if (verbosity > 0) { + process.stderr.write(message); + } + }); + + await new Promise(resolve => { + child.on('close', async (code) => { + if (code !== 0) { + throw new Error('Watch exited with error'); + } + child.stdin?.end(); + await watcher.close(); + resolve(code); + }); + }); + } + + /** + * Perform a integ test case deployment, including + * peforming the update workflow + */ + private deploy( + deployArgs: DeployOptions, + updateWorkflowEnabled: boolean, + testCaseName: string, + ): AssertionResults | undefined { + const actualTestCase = this.actualTestSuite.testSuite[testCaseName]; + try { + if (actualTestCase.hooks?.preDeploy) { + actualTestCase.hooks.preDeploy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + // if the update workflow is not disabled, first + // perform a deployment with the exising snapshot + // then perform a deployment (which will be a stack update) + // with the current integration test + // We also only want to run the update workflow if there is an existing + // snapshot (otherwise there is nothing to update) + if (updateWorkflowEnabled && this.hasSnapshot() && + (this.expectedTestSuite && testCaseName in this.expectedTestSuite?.testSuite)) { + // make sure the snapshot is the latest from 'origin' + this.checkoutSnapshot(); + const expectedTestCase = this.expectedTestSuite.testSuite[testCaseName]; + this.cdk.deploy({ + ...deployArgs, + stacks: expectedTestCase.stacks, + ...expectedTestCase?.cdkCommandOptions?.deploy?.args, + context: this.getContext(expectedTestCase?.cdkCommandOptions?.deploy?.args?.context), + app: path.relative(this.directory, this.snapshotDir), + lookups: this.expectedTestSuite?.enableLookups, + }); + } + // now deploy the "actual" test. + this.cdk.deploy({ + ...deployArgs, + lookups: this.actualTestSuite.enableLookups, + stacks: [ + ...actualTestCase.stacks, + ], + output: path.relative(this.directory, this.cdkOutDir), + ...actualTestCase?.cdkCommandOptions?.deploy?.args, + context: this.getContext(actualTestCase?.cdkCommandOptions?.deploy?.args?.context), + app: this.cdkApp, + }); + + // If there are any assertions + // deploy the assertion stack as well + // This is separate from the above deployment because we want to + // set `rollback: false`. This allows the assertion stack to deploy all the + // assertions instead of failing at the first failed assertion + // combining it with the above deployment would prevent any replacement updates + if (actualTestCase.assertionStack) { + this.cdk.deploy({ + ...deployArgs, + lookups: this.actualTestSuite.enableLookups, + stacks: [ + actualTestCase.assertionStack, + ], + rollback: false, + output: path.relative(this.directory, this.cdkOutDir), + ...actualTestCase?.cdkCommandOptions?.deploy?.args, + outputsFile: path.relative(this.directory, path.join(this.cdkOutDir, 'assertion-results.json')), + context: this.getContext(actualTestCase?.cdkCommandOptions?.deploy?.args?.context), + app: this.cdkApp, + }); + } + + if (actualTestCase.hooks?.postDeploy) { + actualTestCase.hooks.postDeploy.forEach(cmd => { + exec(chunks(cmd), { + cwd: path.dirname(this.snapshotDir), + }); + }); + } + + if (actualTestCase.assertionStack && actualTestCase.assertionStackName) { + return this.processAssertionResults( + path.join(this.cdkOutDir, 'assertion-results.json'), + actualTestCase.assertionStackName, + actualTestCase.assertionStack, + ); + } + } catch (e) { + this.parseError(e, + actualTestCase.cdkCommandOptions?.deploy?.expectError ?? false, + actualTestCase.cdkCommandOptions?.deploy?.expectedMessage, + ); + } + return; + } + + /** + * Process the outputsFile which contains the assertions results as stack + * outputs + */ + private processAssertionResults(file: string, assertionStackName: string, assertionStackId: string): AssertionResults | undefined { + const results: AssertionResults = {}; + if (fs.existsSync(file)) { + try { + const outputs: { [key: string]: { [key: string]: string } } = fs.readJSONSync(file); + + if (assertionStackName in outputs) { + for (const [assertionId, result] of Object.entries(outputs[assertionStackName])) { + if (assertionId.startsWith('AssertionResults')) { + const assertionResult: AssertionResult = JSON.parse(result.replace(/\n/g, '\\n')); + if (assertionResult.status === 'fail' || assertionResult.status === 'success') { + results[assertionId] = assertionResult; + } + } + } + } + } catch (e) { + // if there are outputs, but they cannot be processed, then throw an error + // so that the test fails + results[assertionStackId] = { + status: 'fail', + message: `error processing assertion results: ${e}`, + }; + } finally { + // remove the outputs file so it is not part of the snapshot + // it will contain env specific information from values + // resolved at deploy time + fs.unlinkSync(file); + } + } + return Object.keys(results).length > 0 ? results : undefined; + } + + /** + * Parses an error message returned from a CDK command + */ + private parseError(e: unknown, expectError: boolean, expectedMessage?: string) { + if (expectError) { + if (expectedMessage) { + const message = (e as Error).message; + if (!message.match(expectedMessage)) { + throw (e); + } + } + } else { + throw e; + } + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integ-test-suite.ts b/packages/@aws-cdk/integ-runner/lib/runner/integ-test-suite.ts new file mode 100644 index 000000000..534c3a7c6 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/integ-test-suite.ts @@ -0,0 +1,257 @@ +import * as osPath from 'path'; +import type { ICdk, ListOptions } from '@aws-cdk/cdk-cli-wrapper'; +import type { TestCase, TestOptions, IntegManifest } from '@aws-cdk/cloud-assembly-schema'; +import { Manifest } from '@aws-cdk/cloud-assembly-schema'; +import * as fs from 'fs-extra'; +import { IntegManifestReader } from './private/integ-manifest'; + +const CDK_INTEG_STACK_PRAGMA = '/// !cdk-integ'; +const PRAGMA_PREFIX = 'pragma:'; +const SET_CONTEXT_PRAGMA_PREFIX = 'pragma:set-context:'; +const VERIFY_ASSET_HASHES = 'pragma:include-assets-hashes'; +const DISABLE_UPDATE_WORKFLOW = 'pragma:disable-update-workflow'; +const ENABLE_LOOKUPS_PRAGMA = 'pragma:enable-lookups'; + +/** + * Represents an integration test + */ +export type TestSuite = { [testName: string]: TestCase }; + +export type TestSuiteType = 'test-suite' | 'legacy-test-suite'; + +/** + * Helper class for working with Integration tests + * This requires an `integ.json` file in the snapshot + * directory. For legacy test cases use LegacyIntegTestCases + */ +export class IntegTestSuite { + /** + * Loads integ tests from a snapshot directory + */ + public static fromPath(path: string): IntegTestSuite { + const reader = IntegManifestReader.fromPath(path); + return new IntegTestSuite( + reader.tests.enableLookups, + reader.tests.testCases, + reader.tests.synthContext, + ); + } + + public readonly type: TestSuiteType = 'test-suite'; + + constructor( + public readonly enableLookups: boolean, + public readonly testSuite: TestSuite, + public readonly synthContext?: { [name: string]: string }, + ) { + } + + /** + * Returns a list of stacks that have stackUpdateWorkflow disabled + */ + public getStacksWithoutUpdateWorkflow(): string[] { + return Object.values(this.testSuite) + .filter(testCase => !(testCase.stackUpdateWorkflow ?? true)) + .flatMap((testCase: TestCase) => testCase.stacks); + } + + /** + * Returns test case options for a given stack + */ + public getOptionsForStack(stackId: string): TestOptions | undefined { + for (const testCase of Object.values(this.testSuite ?? {})) { + if (testCase.stacks.includes(stackId)) { + return { + hooks: testCase.hooks, + regions: testCase.regions, + diffAssets: testCase.diffAssets ?? false, + allowDestroy: testCase.allowDestroy, + cdkCommandOptions: testCase.cdkCommandOptions, + stackUpdateWorkflow: testCase.stackUpdateWorkflow ?? true, + }; + } + } + return undefined; + } + + /** + * Get a list of stacks in the test suite + */ + public get stacks(): string[] { + return Object.values(this.testSuite).flatMap(testCase => testCase.stacks); + } +} + +/** + * Options for a reading a legacy test case manifest + */ +export interface LegacyTestCaseConfig { + /** + * The name of the test case + */ + readonly testName: string; + + /** + * Options to use when performing `cdk list` + * This is used to determine the name of the stacks + * in the test case + */ + readonly listOptions: ListOptions; + + /** + * An instance of the CDK CLI (e.g. CdkCliWrapper) + */ + readonly cdk: ICdk; + + /** + * The path to the integration test file + * i.e. integ.test.js + */ + readonly integSourceFilePath: string; +} + +/** + * Helper class for creating an integ manifest for legacy + * test cases, i.e. tests without a `integ.json`. + */ +export class LegacyIntegTestSuite extends IntegTestSuite { + /** + * Returns the single test stack to use. + * + * If the test has a single stack, it will be chosen. Otherwise a pragma is expected within the + * test file the name of the stack: + * + * @example + * + * /// !cdk-integ + * + */ + public static fromLegacy(config: LegacyTestCaseConfig): LegacyIntegTestSuite { + const pragmas = this.pragmas(config.integSourceFilePath); + const tests: TestCase = { + stacks: [], + diffAssets: pragmas.includes(VERIFY_ASSET_HASHES), + stackUpdateWorkflow: !pragmas.includes(DISABLE_UPDATE_WORKFLOW), + }; + const pragma = this.readStackPragma(config.integSourceFilePath); + if (pragma.length > 0) { + tests.stacks.push(...pragma); + } else { + const options: ListOptions = { + ...config.listOptions, + notices: false, + }; + const stacks = (config.cdk.list(options)).split('\n'); + if (stacks.length !== 1) { + throw new Error('"cdk-integ" can only operate on apps with a single stack.\n\n' + + ' If your app has multiple stacks, specify which stack to select by adding this to your test source:\n\n' + + ` ${CDK_INTEG_STACK_PRAGMA} STACK ...\n\n` + + ` Available stacks: ${stacks.join(' ')} (wildcards are also supported)\n`); + } + if (stacks.length === 1 && stacks[0] === '') { + throw new Error(`No stack found for test ${config.testName}`); + } + tests.stacks.push(...stacks); + } + + return new LegacyIntegTestSuite( + pragmas.includes(ENABLE_LOOKUPS_PRAGMA), + { + [config.testName]: tests, + }, + LegacyIntegTestSuite.getPragmaContext(config.integSourceFilePath), + ); + } + + public static getPragmaContext(integSourceFilePath: string): Record { + const ctxPragmaContext: Record = {}; + + // apply context from set-context pragma + // usage: pragma:set-context:key=value + const ctxPragmas = (this.pragmas(integSourceFilePath)).filter(p => p.startsWith(SET_CONTEXT_PRAGMA_PREFIX)); + for (const p of ctxPragmas) { + const instruction = p.substring(SET_CONTEXT_PRAGMA_PREFIX.length); + const [key, value] = instruction.split('='); + if (key == null || value == null) { + throw new Error(`invalid "set-context" pragma syntax. example: "pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true" got: ${p}`); + } + + ctxPragmaContext[key] = value; + } + return { + ...ctxPragmaContext, + }; + } + + /** + * Reads stack names from the "!cdk-integ" pragma. + * + * Every word that's NOT prefixed by "pragma:" is considered a stack name. + * + * @example + * + * /// !cdk-integ + */ + private static readStackPragma(integSourceFilePath: string): string[] { + return (this.readIntegPragma(integSourceFilePath)).filter(p => !p.startsWith(PRAGMA_PREFIX)); + } + + /** + * Read arbitrary cdk-integ pragma directives + * + * Reads the test source file and looks for the "!cdk-integ" pragma. If it exists, returns it's + * contents. This allows integ tests to supply custom command line arguments to "cdk deploy" and "cdk synth". + * + * @example + * + * /// !cdk-integ [...] + */ + private static readIntegPragma(integSourceFilePath: string): string[] { + const source = fs.readFileSync(integSourceFilePath, { encoding: 'utf-8' }); + const pragmaLine = source.split('\n').find(x => x.startsWith(CDK_INTEG_STACK_PRAGMA + ' ')); + if (!pragmaLine) { + return []; + } + + const args = pragmaLine.substring(CDK_INTEG_STACK_PRAGMA.length).trim().split(' '); + if (args.length === 0) { + throw new Error(`Invalid syntax for cdk-integ pragma. Usage: "${CDK_INTEG_STACK_PRAGMA} [STACK] [pragma:PRAGMA] [...]"`); + } + return args; + } + + /** + * Return the non-stack pragmas + * + * These are all pragmas that start with "pragma:". + * + * For backwards compatibility reasons, all pragmas that DON'T start with this + * string are considered to be stack names. + */ + private static pragmas(integSourceFilePath: string): string[] { + return (this.readIntegPragma(integSourceFilePath)).filter(p => p.startsWith(PRAGMA_PREFIX)); + } + + public readonly type: TestSuiteType = 'legacy-test-suite'; + + constructor( + public readonly enableLookups: boolean, + public readonly testSuite: TestSuite, + public readonly synthContext?: { [name: string]: string }, + ) { + super(enableLookups, testSuite); + } + + /** + * Save the integ manifest to a directory + */ + public saveManifest(directory: string, context?: Record): void { + const manifest: IntegManifest = { + version: Manifest.version(), + testCases: this.testSuite, + synthContext: context, + enableLookups: this.enableLookups, + }; + Manifest.saveIntegManifest(manifest, osPath.join(directory, IntegManifestReader.DEFAULT_FILENAME)); + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts b/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts new file mode 100644 index 000000000..a9927b320 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts @@ -0,0 +1,373 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; + +const CDK_OUTDIR_PREFIX = 'cdk-integ.out'; + +/** + * Represents a single integration test + * + * This type is a data-only structure, so it can trivially be passed to workers. + * Derived attributes are calculated using the `IntegTest` class. + */ +export interface IntegTestInfo { + /** + * Path to the file to run + * + * Path is relative to the current working directory. + */ + readonly fileName: string; + + /** + * The root directory we discovered this test from + * + * Path is relative to the current working directory. + */ + readonly discoveryRoot: 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. + * + * @default - test run command will be `node {filePath}` + */ + readonly appCommand?: string; + + /** + * true if this test is running in watch mode + * + * @default false + */ + readonly watch?: boolean; +} + +/** + * Derived information for IntegTests + */ +export class IntegTest { + /** + * The name of the file to run + * + * Path is relative to the current working directory. + */ + public readonly fileName: string; + + /** + * Relative path to the file to run + * + * Relative from the "discovery root". + */ + public readonly discoveryRelativeFileName: string; + + /** + * The absolute path to the file + */ + public readonly absoluteFileName: string; + + /** + * The normalized name of the test. This name + * will be the same regardless of what directory the tool + * is run from. + */ + public readonly normalizedTestName: string; + + /** + * Directory the test is in + */ + public readonly directory: string; + + /** + * Display name for the test + * + * Depends on the discovery directory. + * + * Looks like `integ.mytest` or `package/test/integ.mytest`. + */ + public readonly testName: string; + + /** + * Path of the snapshot directory for this test + */ + public readonly snapshotDir: string; + + /** + * Path to the temporary output directory for this test + */ + public readonly temporaryOutputDir: 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. + * + * @default - test run command will be `node {filePath}` + */ + readonly appCommand: string; + + constructor(public readonly info: IntegTestInfo) { + this.appCommand = info.appCommand ?? 'node {filePath}'; + this.absoluteFileName = path.resolve(info.fileName); + this.fileName = path.relative(process.cwd(), info.fileName); + + const parsed = path.parse(this.fileName); + this.discoveryRelativeFileName = path.relative(info.discoveryRoot, info.fileName); + // if `--watch` then we need the directory to be the cwd + this.directory = info.watch ? process.cwd() : parsed.dir; + + // if we are running in a package directory then just use the fileName + // as the testname, but if we are running in a parent directory with + // multiple packages then use the directory/filename as the testname + // + // Looks either like `integ.mytest` or `package/test/integ.mytest`. + const relDiscoveryRoot = path.relative(process.cwd(), info.discoveryRoot); + this.testName = this.directory === path.join(relDiscoveryRoot, 'test') || this.directory === path.join(relDiscoveryRoot) + ? parsed.name + : path.join(path.relative(this.info.discoveryRoot, parsed.dir), parsed.name); + + this.normalizedTestName = parsed.name; + this.snapshotDir = path.join(parsed.dir, `${parsed.base}.snapshot`); + this.temporaryOutputDir = path.join(parsed.dir, `${CDK_OUTDIR_PREFIX}.${parsed.base}.snapshot`); + } + + /** + * Whether this test matches the user-given name + * + * We are very lenient here. A name matches if it matches: + * + * - The CWD-relative filename + * - The discovery root-relative filename + * - The suite name + * - The absolute filename + */ + public matches(name: string) { + return [ + this.fileName, + this.discoveryRelativeFileName, + this.testName, + this.absoluteFileName, + ].includes(name); + } +} + +/** + * Configuration options how integration test files are discovered + */ +export interface IntegrationTestsDiscoveryOptions { + /** + * If this is set to true then the list of tests + * provided will be excluded + * + * @default false + */ + readonly exclude?: boolean; + + /** + * List of tests to include (or exclude if `exclude=true`) + * + * @default - all matched files + */ + readonly tests?: string[]; + + /** + * A map of of the app commands to run integration tests with, + * and the regex patterns matching the integration test files each app command. + * + * If the app command contains {filePath}, the test file names will be substituted at that place in the command for each run. + */ + readonly testCases: { + [app: string]: string[]; + }; +} + +/** + * Returns the name of the Python executable for the current OS + */ +function pythonExecutable() { + let python = 'python3'; + if (process.platform === 'win32') { + python = 'python'; + } + return python; +} + +/** + * Discover integration tests + */ +export class IntegrationTests { + constructor(private readonly directory: string) { + } + + /** + * Get integration tests discovery options from CLI options + */ + public async fromCliOptions(options: { + app?: string; + exclude?: boolean; + language?: string[]; + testRegex?: string[]; + tests?: string[]; + }): Promise { + const baseOptions = { + tests: options.tests, + exclude: options.exclude, + }; + + // Explicitly set both, app and test-regex + if (options.app && options.testRegex) { + return this.discover({ + testCases: { + [options.app]: options.testRegex, + }, + ...baseOptions, + }); + } + + // Use the selected presets + if (!options.app && !options.testRegex) { + // Only case with multiple languages, i.e. the only time we need to check the special case + const ignoreUncompiledTypeScript = options.language?.includes('javascript') && options.language?.includes('typescript'); + + return this.discover({ + testCases: this.getLanguagePresets(options.language), + ...baseOptions, + }, ignoreUncompiledTypeScript); + } + + // 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 this.discover({ + 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 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$']], + go: ['go run {filePath}', ['^integ_.*\\.go$']], + }; + + return languagePresets[language]; + } + + /** + * Get the config for all selected languages + */ + private getLanguagePresets(languages: string[] = []) { + return Object.fromEntries( + languages + .map(language => this.getLanguagePreset(language)) + .filter(Boolean), + ); + } + + /** + * If the user provides a list of tests, these can either be a list of tests to include or a list of tests to exclude. + * + * - If it is a list of tests to include then we discover all available tests and check whether they have provided valid tests. + * If they have provided a test name that we don't find, then we write out that error message. + * - If it is a list of tests to exclude, then we discover all available tests and filter out the tests that were provided by the user. + */ + private filterTests(discoveredTests: IntegTest[], requestedTests?: string[], exclude?: boolean): IntegTest[] { + if (!requestedTests) { + 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) + }); + + // If not excluding, all patterns must have matched at least one test + if (!exclude) { + const unmatchedPatterns = requestedTests.filter(pattern => !discoveredTests.some(t => t.matches(pattern))); + for (const unmatched of unmatchedPatterns) { + process.stderr.write(`No such integ test: ${unmatched}\n`); + } + if (unmatchedPatterns.length > 0) { + process.stderr.write(`Available tests: ${discoveredTests.map(t => t.discoveryRelativeFileName).join(' ')}\n`); + return []; + } + } + + return allTests; + } + + /** + * Takes an optional list of tests to look for, otherwise + * it will look for all tests from the directory + * + * @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). + */ + private async discover(options: IntegrationTestsDiscoveryOptions, ignoreUncompiledTypeScript: boolean = false): Promise { + const files = await this.readTree(); + + const testCases = 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, + })), + ); + + const discoveredTests = ignoreUncompiledTypeScript ? this.filterUncompiledTypeScript(testCases) : testCases; + + return this.filterTests(discoveredTests, options.tests, options.exclude); + } + + private filterUncompiledTypeScript(testCases: IntegTest[]): IntegTest[] { + const jsTestCases = testCases.filter(t => t.fileName.endsWith('.js')); + + return testCases + // Remove all TypeScript test cases (ending in .ts) + // for which a compiled version is present (same name, ending in .js) + .filter((tsCandidate) => { + if (!tsCandidate.fileName.endsWith('.ts')) { + return true; + } + return jsTestCases.findIndex(jsTest => jsTest.testName === tsCandidate.testName) === -1; + }); + } + + private async readTree(): Promise { + const ret = new Array(); + + async function recurse(dir: string) { + const files = await fs.readdir(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + const statf = await fs.stat(fullPath); + if (statf.isFile()) { + ret.push(fullPath); + } + if (statf.isDirectory()) { + await recurse(fullPath); + } + } + } + + await recurse(this.directory); + return ret; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts new file mode 100644 index 000000000..b16b59cac --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/cloud-assembly.ts @@ -0,0 +1,267 @@ +import * as path from 'path'; +import type { AssemblyManifest, AwsCloudFormationStackProperties, ArtifactManifest, MetadataEntry, AssetManifestProperties, ContainerImageAssetMetadataEntry, FileAssetMetadataEntry } from '@aws-cdk/cloud-assembly-schema'; +import { Manifest, ArtifactType, ArtifactMetadataEntryType } from '@aws-cdk/cloud-assembly-schema'; +import type { FileManifestEntry, DockerImageManifestEntry } from 'cdk-assets/lib/asset-manifest'; +import { AssetManifest } from 'cdk-assets/lib/asset-manifest'; +import * as fs from 'fs-extra'; + +/** + * Trace information for stack + * map of resource logicalId to trace message + */ +export type StackTrace = Map; + +/** + * Trace information for a assembly + * + * map of stackId to StackTrace + */ +export type ManifestTrace = Map; + +/** + * Reads a Cloud Assembly manifest + */ +export class AssemblyManifestReader { + public static readonly DEFAULT_FILENAME = 'manifest.json'; + + /** + * Reads a Cloud Assembly manifest from a file + */ + public static fromFile(fileName: string): AssemblyManifestReader { + try { + const obj = Manifest.loadAssemblyManifest(fileName); + return new AssemblyManifestReader(path.dirname(fileName), obj, fileName); + } catch (e: any) { + throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); + } + } + + /** + * Reads a Cloud Assembly manifest from a file or a directory + * If the given filePath is a directory then it will look for + * a file within the directory with the DEFAULT_FILENAME + */ + public static fromPath(filePath: string): AssemblyManifestReader { + let st; + try { + st = fs.statSync(filePath); + } catch (e: any) { + throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); + } + if (st.isDirectory()) { + return AssemblyManifestReader.fromFile(path.join(filePath, AssemblyManifestReader.DEFAULT_FILENAME)); + } + return AssemblyManifestReader.fromFile(filePath); + } + + /** + * The directory where the manifest was found + */ + public readonly directory: string; + + constructor(directory: string, private readonly manifest: AssemblyManifest, private readonly manifestFileName: string) { + this.directory = directory; + } + + /** + * Get the stacks from the manifest + * returns a map of artifactId to CloudFormation template + */ + public get stacks(): Record { + const stacks: Record = {}; + for (const [artifactId, artifact] of Object.entries(this.manifest.artifacts ?? {})) { + if (artifact.type !== ArtifactType.AWS_CLOUDFORMATION_STACK) { + continue; + } + const props = artifact.properties as AwsCloudFormationStackProperties; + + const template = fs.readJSONSync(path.resolve(this.directory, props.templateFile)); + stacks[artifactId] = template; + } + return stacks; + } + + /** + * Get the nested stacks for a given stack + * returns a map of artifactId to CloudFormation template + */ + public getNestedStacksForStack(stackId: string): Record { + const nestedTemplates: string[] = this.getAssetManifestsForStack(stackId).flatMap( + manifest => manifest.files + .filter(asset => asset.source.path?.endsWith('.nested.template.json')) + .map(asset => asset.source.path!), + ); + + const nestedStacks: Record = Object.fromEntries(nestedTemplates.map(templateFile => ([ + templateFile.split('.', 1)[0], + fs.readJSONSync(path.resolve(this.directory, templateFile)), + ]))); + + return nestedStacks; + } + + /** + * Write trace data to the assembly manifest metadata + */ + public recordTrace(trace: ManifestTrace): void { + const newManifest = { + ...this.manifest, + artifacts: this.renderArtifacts(trace), + }; + Manifest.saveAssemblyManifest(newManifest, this.manifestFileName); + } + + /** + * Return a list of assets for a given stack + */ + public getAssetIdsForStack(stackId: string): string[] { + const assets: string[] = []; + for (const artifact of Object.values(this.manifest.artifacts ?? {})) { + if (artifact.type === ArtifactType.ASSET_MANIFEST && (artifact.properties as AssetManifestProperties)?.file === `${stackId}.assets.json`) { + assets.push(...this.assetsFromAssetManifest(artifact).map(asset => asset.id.assetId)); + } else if (artifact.type === ArtifactType.AWS_CLOUDFORMATION_STACK) { + assets.push(...this.assetsFromAssemblyManifest(artifact).map(asset => asset.id)); + } + } + return assets; + } + + /** + * For a given stackId return a list of assets that belong to the stack + */ + public getAssetLocationsForStack(stackId: string): string[] { + const assets: string[] = []; + for (const artifact of Object.values(this.manifest.artifacts ?? {})) { + if (artifact.type === ArtifactType.ASSET_MANIFEST && (artifact.properties as AssetManifestProperties)?.file === `${stackId}.assets.json`) { + assets.push(...this.assetsFromAssetManifest(artifact).flatMap(asset => { + if (asset.type === 'file' && !asset.source.path?.endsWith('nested.template.json')) { + return asset.source.path!; + } else if (asset.type !== 'file') { + return asset.source.directory!; + } + return []; + })); + } else if (artifact.type === ArtifactType.AWS_CLOUDFORMATION_STACK) { + assets.push(...this.assetsFromAssemblyManifest(artifact).map(asset => asset.path)); + } + } + return assets; + } + + /** + * Return a list of asset artifacts for a given stack + */ + public getAssetManifestsForStack(stackId: string): AssetManifest[] { + return Object.values(this.manifest.artifacts ?? {}) + .filter(artifact => + artifact.type === ArtifactType.ASSET_MANIFEST && (artifact.properties as AssetManifestProperties)?.file === `${stackId}.assets.json`) + .map(artifact => { + const fileName = (artifact.properties as AssetManifestProperties).file; + return AssetManifest.fromFile(path.join(this.directory, fileName)); + }); + } + + /** + * Get a list of assets from the assembly manifest + */ + private assetsFromAssemblyManifest(artifact: ArtifactManifest): (ContainerImageAssetMetadataEntry | FileAssetMetadataEntry)[] { + const assets: (ContainerImageAssetMetadataEntry | FileAssetMetadataEntry)[] = []; + for (const metadata of Object.values(artifact.metadata ?? {})) { + metadata.forEach(data => { + if (data.type === ArtifactMetadataEntryType.ASSET) { + const asset = (data.data as ContainerImageAssetMetadataEntry | FileAssetMetadataEntry); + if (asset.path.startsWith('asset.')) { + assets.push(asset); + } + } + }); + } + return assets; + } + + /** + * Get a list of assets from the asset manifest + */ + private assetsFromAssetManifest(artifact: ArtifactManifest): (FileManifestEntry | DockerImageManifestEntry)[] { + const assets: (FileManifestEntry | DockerImageManifestEntry)[] = []; + const fileName = (artifact.properties as AssetManifestProperties).file; + const assetManifest = AssetManifest.fromFile(path.join(this.directory, fileName)); + assetManifest.entries.forEach(entry => { + if (entry.type === 'file') { + const source = (entry as FileManifestEntry).source; + if (source.path && (source.path.startsWith('asset.') || source.path.endsWith('nested.template.json'))) { + assets.push(entry as FileManifestEntry); + } + } else if (entry.type === 'docker-image') { + const source = (entry as DockerImageManifestEntry).source; + if (source.directory && source.directory.startsWith('asset.')) { + assets.push(entry as DockerImageManifestEntry); + } + } + }); + return assets; + } + + /** + * Clean the manifest of any unneccesary data. Currently that includes + * the metadata trace information since this includes trace information like + * file system locations and file lines that will change depending on what machine the test is run on + */ + public cleanManifest(): void { + const newManifest = { + ...this.manifest, + artifacts: this.renderArtifacts(), + }; + Manifest.saveAssemblyManifest(newManifest, this.manifestFileName); + } + + private renderArtifactMetadata(artifact: ArtifactManifest, trace?: StackTrace): { [id: string]: MetadataEntry[] } | undefined { + const newMetadata: { [id: string]: MetadataEntry[] } = {}; + if (!artifact.metadata) return artifact.metadata; + for (const [metadataId, metadataEntry] of Object.entries(artifact.metadata ?? {})) { + newMetadata[metadataId] = metadataEntry.map((meta: MetadataEntry) => { + if (meta.type === 'aws:cdk:logicalId' && trace && meta.data) { + const traceData = trace.get(meta.data.toString()); + if (traceData) { + trace.delete(meta.data.toString()); + return { + type: meta.type, + data: meta.data, + trace: [traceData], + }; + } + } + // return metadata without the trace data + return { + type: meta.type, + data: meta.data, + }; + }); + } + if (trace && trace.size > 0) { + for (const [id, data] of trace.entries()) { + newMetadata[id] = [{ + type: 'aws:cdk:logicalId', + data: id, + trace: [data], + }]; + } + } + return newMetadata; + } + + private renderArtifacts(trace?: ManifestTrace): { [id: string]: ArtifactManifest } | undefined { + const newArtifacts: { [id: string]: ArtifactManifest } = {}; + for (const [artifactId, artifact] of Object.entries(this.manifest.artifacts ?? {})) { + let stackTrace: StackTrace | undefined = undefined; + if (artifact.type === ArtifactType.AWS_CLOUDFORMATION_STACK && trace) { + stackTrace = trace.get(artifactId); + } + newArtifacts[artifactId] = { + ...artifact, + metadata: this.renderArtifactMetadata(artifact, stackTrace), + }; + } + return newArtifacts; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts b/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts new file mode 100644 index 000000000..bb6deff82 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/private/integ-manifest.ts @@ -0,0 +1,86 @@ +import * as path from 'path'; +import type { IntegManifest, TestCase } from '@aws-cdk/cloud-assembly-schema'; +import { Manifest } from '@aws-cdk/cloud-assembly-schema'; +import * as fs from 'fs-extra'; + +/** + * Test case configuration read from the integ manifest + */ +export interface IntegTestConfig { + /** + * Test cases contained in this integration test + */ + readonly testCases: { [testCaseName: string]: TestCase }; + + /** + * Whether to enable lookups for this test + * + * @default false + */ + readonly enableLookups: boolean; + + /** + * Additional context to use when performing + * a synth. Any context provided here will override + * any default context + * + * @default - no additional context + */ + readonly synthContext?: { [name: string]: string }; +} + +/** + * Reads an integration tests manifest + */ +export class IntegManifestReader { + public static readonly DEFAULT_FILENAME = 'integ.json'; + + /** + * Reads an integration test manifest from the specified file + */ + public static fromFile(fileName: string): IntegManifestReader { + try { + const obj = Manifest.loadIntegManifest(fileName); + return new IntegManifestReader(path.dirname(fileName), obj); + } catch (e: any) { + throw new Error(`Cannot read integ manifest '${fileName}': ${e.message}`); + } + } + + /** + * Reads a Integration test manifest from a file or a directory + * If the given filePath is a directory then it will look for + * a file within the directory with the DEFAULT_FILENAME + */ + public static fromPath(filePath: string): IntegManifestReader { + let st; + try { + st = fs.statSync(filePath); + } catch (e: any) { + throw new Error(`Cannot read integ manifest at '${filePath}': ${e.message}`); + } + if (st.isDirectory()) { + return IntegManifestReader.fromFile(path.join(filePath, IntegManifestReader.DEFAULT_FILENAME)); + } + return IntegManifestReader.fromFile(filePath); + } + + /** + * The directory where the manifest was found + */ + public readonly directory: string; + constructor(directory: string, private readonly manifest: IntegManifest) { + this.directory = directory; + } + + /** + * List of integration tests in the manifest + */ + public get tests(): IntegTestConfig { + return { + testCases: this.manifest.testCases, + enableLookups: this.manifest.enableLookups ?? false, + synthContext: this.manifest.synthContext, + }; + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts new file mode 100644 index 000000000..c6e28011d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts @@ -0,0 +1,448 @@ +/* eslint-disable @cdklabs/no-literal-partition */ +import * as path from 'path'; +import type { ICdk } from '@aws-cdk/cdk-cli-wrapper'; +import { CdkCliWrapper } from '@aws-cdk/cdk-cli-wrapper'; +import type { TestCase, DefaultCdkOptions } from '@aws-cdk/cloud-assembly-schema'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, TARGET_PARTITIONS } from '@aws-cdk/cx-api'; +import * as fs from 'fs-extra'; +import { IntegTestSuite, LegacyIntegTestSuite } from './integ-test-suite'; +import type { IntegTest } from './integration-tests'; +import * as recommendedFlagsFile from '../recommended-feature-flags.json'; +import { flatten } from '../utils'; +import type { ManifestTrace } from './private/cloud-assembly'; +import { AssemblyManifestReader } from './private/cloud-assembly'; +import type { DestructiveChange } from '../workers/common'; + +const DESTRUCTIVE_CHANGES = '!!DESTRUCTIVE_CHANGES:'; + +/** + * Options for creating an integration test runner + */ +export interface IntegRunnerOptions { + /** + * Information about the test to run + */ + readonly test: IntegTest; + + /** + * The AWS profile to use when invoking the CDK CLI + * + * @default - no profile is passed, the default profile is used + */ + readonly profile?: string; + + /** + * Additional environment variables that will be available + * to the CDK CLI + * + * @default - no additional environment variables + */ + readonly env?: { [name: string]: string }; + + /** + * tmp cdk.out directory + * + * @default - directory will be `cdk-integ.out.${testName}` + */ + readonly integOutDir?: string; + + /** + * Instance of the CDK CLI to use + * + * @default - CdkCliWrapper + */ + readonly cdk?: ICdk; + + /** + * Show output from running integration tests + * + * @default false + */ + readonly showOutput?: boolean; +} + +/** + * The different components of a test name + */ +/** + * Represents an Integration test runner + */ +export abstract class IntegRunner { + /** + * The directory where the snapshot will be stored + */ + public readonly snapshotDir: string; + + /** + * An instance of the CDK CLI + */ + public readonly cdk: ICdk; + + /** + * Pretty name of the test + */ + public readonly testName: string; + + /** + * The value used in the '--app' CLI parameter + * + * Path to the integ test source file, relative to `this.directory`. + */ + protected readonly cdkApp: string; + + /** + * The path where the `cdk.context.json` file + * will be created + */ + protected readonly cdkContextPath: string; + + /** + * The test suite from the existing snapshot + */ + protected readonly expectedTestSuite?: IntegTestSuite | LegacyIntegTestSuite; + + /** + * The test suite from the new "actual" snapshot + */ + protected readonly actualTestSuite: IntegTestSuite | LegacyIntegTestSuite; + + /** + * The working directory that the integration tests will be + * executed from + */ + protected readonly directory: string; + + /** + * The test to run + */ + protected readonly test: IntegTest; + + /** + * Default options to pass to the CDK CLI + */ + protected readonly defaultArgs: DefaultCdkOptions = { + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + }; + + /** + * The directory where the CDK will be synthed to + * + * Relative to cwd. + */ + protected readonly cdkOutDir: string; + + protected readonly profile?: string; + + protected _destructiveChanges?: DestructiveChange[]; + private legacyContext?: Record; + protected isLegacyTest?: boolean; + + constructor(options: IntegRunnerOptions) { + this.test = options.test; + this.directory = this.test.directory; + this.testName = this.test.testName; + this.snapshotDir = this.test.snapshotDir; + this.cdkContextPath = path.join(this.directory, 'cdk.context.json'); + + this.cdk = options.cdk ?? new CdkCliWrapper({ + directory: this.directory, + showOutput: options.showOutput, + env: { + ...options.env, + }, + }); + this.cdkOutDir = options.integOutDir ?? this.test.temporaryOutputDir; + + const testRunCommand = this.test.appCommand; + this.cdkApp = testRunCommand.replace('{filePath}', path.relative(this.directory, this.test.fileName)); + + this.profile = options.profile; + if (this.hasSnapshot()) { + this.expectedTestSuite = this.loadManifest(); + } + this.actualTestSuite = this.generateActualSnapshot(); + } + + /** + * Return the list of expected (i.e. existing) test cases for this integration test + */ + public expectedTests(): { [testName: string]: TestCase } | undefined { + return this.expectedTestSuite?.testSuite; + } + + /** + * Return the list of actual (i.e. new) test cases for this integration test + */ + public actualTests(): { [testName: string]: TestCase } | undefined { + return this.actualTestSuite.testSuite; + } + + /** + * Generate a new "actual" snapshot which will be compared to the + * existing "expected" snapshot + * This will synth and then load the integration test manifest + */ + public generateActualSnapshot(): IntegTestSuite | LegacyIntegTestSuite { + this.cdk.synthFast({ + execCmd: this.cdkApp.split(' '), + env: { + ...DEFAULT_SYNTH_OPTIONS.env, + // we don't know the "actual" context yet (this method is what generates it) so just + // use the "expected" context. This is only run in order to read the manifest + CDK_CONTEXT_JSON: JSON.stringify(this.getContext(this.expectedTestSuite?.synthContext)), + }, + output: path.relative(this.directory, this.cdkOutDir), + }); + const manifest = this.loadManifest(this.cdkOutDir); + // after we load the manifest remove the tmp snapshot + // so that it doesn't mess up the real snapshot created later + this.cleanup(); + return manifest; + } + + /** + * Returns true if a snapshot already exists for this test + */ + public hasSnapshot(): boolean { + return fs.existsSync(this.snapshotDir); + } + + /** + * Load the integ manifest which contains information + * on how to execute the tests + * First we try and load the manifest from the integ manifest (i.e. integ.json) + * from the cloud assembly. If it doesn't exist, then we fallback to the + * "legacy mode" and create a manifest from pragma + */ + protected loadManifest(dir?: string): IntegTestSuite | LegacyIntegTestSuite { + try { + const testSuite = IntegTestSuite.fromPath(dir ?? this.snapshotDir); + return testSuite; + } catch { + const testCases = LegacyIntegTestSuite.fromLegacy({ + cdk: this.cdk, + testName: this.test.normalizedTestName, + integSourceFilePath: this.test.fileName, + listOptions: { + ...this.defaultArgs, + all: true, + app: this.cdkApp, + profile: this.profile, + output: path.relative(this.directory, this.cdkOutDir), + }, + }); + this.legacyContext = LegacyIntegTestSuite.getPragmaContext(this.test.fileName); + this.isLegacyTest = true; + return testCases; + } + } + + protected cleanup(): void { + const cdkOutPath = this.cdkOutDir; + if (fs.existsSync(cdkOutPath)) { + fs.removeSync(cdkOutPath); + } + } + + /** + * If there are any destructive changes to a stack then this will record + * those in the manifest.json file + */ + private renderTraceData(): ManifestTrace { + const traceData: ManifestTrace = new Map(); + const destructiveChanges = this._destructiveChanges ?? []; + destructiveChanges.forEach(change => { + const trace = traceData.get(change.stackName); + if (trace) { + trace.set(change.logicalId, `${DESTRUCTIVE_CHANGES} ${change.impact}`); + } else { + traceData.set(change.stackName, new Map([ + [change.logicalId, `${DESTRUCTIVE_CHANGES} ${change.impact}`], + ])); + } + }); + return traceData; + } + + /** + * In cases where we do not want to retain the assets, + * for example, if the assets are very large. + * + * Since it is possible to disable the update workflow for individual test + * cases, this needs to first get a list of stacks that have the update workflow + * disabled and then delete assets that relate to that stack. It does that + * by reading the asset manifest for the stack and deleting the asset source + */ + protected removeAssetsFromSnapshot(): void { + const stacks = this.actualTestSuite.getStacksWithoutUpdateWorkflow() ?? []; + const manifest = AssemblyManifestReader.fromPath(this.snapshotDir); + const assets = flatten(stacks.map(stack => { + return manifest.getAssetLocationsForStack(stack) ?? []; + })); + + assets.forEach(asset => { + const fileName = path.join(this.snapshotDir, asset); + if (fs.existsSync(fileName)) { + if (fs.lstatSync(fileName).isDirectory()) { + fs.removeSync(fileName); + } else { + fs.unlinkSync(fileName); + } + } + }); + } + + /** + * Remove the asset cache (.cache/) files from the snapshot. + * These are a cache of the asset zips, but we are fine with + * re-zipping on deploy + */ + protected removeAssetsCacheFromSnapshot(): void { + const files = fs.readdirSync(this.snapshotDir); + files.forEach(file => { + const fileName = path.join(this.snapshotDir, file); + if (fs.lstatSync(fileName).isDirectory() && file === '.cache') { + fs.emptyDirSync(fileName); + fs.rmdirSync(fileName); + } + }); + } + + /** + * Create the new snapshot. + * + * If lookups are enabled, then we need create the snapshot by synthing again + * with the dummy context so that each time the test is run on different machines + * (and with different context/env) the diff will not change. + * + * If lookups are disabled (which means the stack is env agnostic) then just copy + * the assembly that was output by the deployment + */ + protected createSnapshot(): void { + if (fs.existsSync(this.snapshotDir)) { + fs.removeSync(this.snapshotDir); + } + + // if lookups are enabled then we need to synth again + // using dummy context and save that as the snapshot + if (this.actualTestSuite.enableLookups) { + this.cdk.synthFast({ + execCmd: this.cdkApp.split(' '), + env: { + ...DEFAULT_SYNTH_OPTIONS.env, + CDK_CONTEXT_JSON: JSON.stringify(this.getContext(DEFAULT_SYNTH_OPTIONS.context)), + }, + output: path.relative(this.directory, this.snapshotDir), + }); + } else { + fs.moveSync(this.cdkOutDir, this.snapshotDir, { overwrite: true }); + } + + this.cleanupSnapshot(); + } + + /** + * Perform some cleanup steps after the snapshot is created + * Anytime the snapshot needs to be modified after creation + * the logic should live here. + */ + private cleanupSnapshot(): void { + if (fs.existsSync(this.snapshotDir)) { + this.removeAssetsFromSnapshot(); + this.removeAssetsCacheFromSnapshot(); + const assembly = AssemblyManifestReader.fromPath(this.snapshotDir); + assembly.cleanManifest(); + assembly.recordTrace(this.renderTraceData()); + } + + // if this is a legacy test then create an integ manifest + // in the snapshot directory which can be used for the + // update workflow. Save any legacyContext as well so that it can be read + // the next time + if (this.actualTestSuite.type === 'legacy-test-suite') { + (this.actualTestSuite as LegacyIntegTestSuite).saveManifest(this.snapshotDir, this.legacyContext); + } + } + + protected getContext(additionalContext?: Record): Record { + return { + ...currentlyRecommendedAwsCdkLibFlags(), + ...this.legacyContext, + ...additionalContext, + + // We originally had PLANNED to set this to ['aws', 'aws-cn'], but due to a programming mistake + // it was set to everything. In this PR, set it to everything to not mess up all the snapshots. + [TARGET_PARTITIONS]: undefined, + + /* ---------------- THE FUTURE LIVES BELOW---------------------------- + // Restricting to these target partitions makes most service principals synthesize to + // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` + // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what + // most existing integ tests contain, and we want to disturb as few as possible. + // [TARGET_PARTITIONS]: ['aws', 'aws-cn'], + /* ---------------- END OF THE FUTURE ------------------------------- */ + }; + } +} + +// Default context we run all integ tests with, so they don't depend on the +// account of the exercising user. +export const DEFAULT_SYNTH_OPTIONS = { + context: { + [AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY]: ['test-region-1a', 'test-region-1b', 'test-region-1c'], + 'availability-zones:account=12345678:region=test-region': ['test-region-1a', 'test-region-1b', 'test-region-1c'], + 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', + 'ssm:account=12345678:parameterName=/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:region=test-region': 'ami-1234', + 'ssm:account=12345678:parameterName=/aws/service/ecs/optimized-ami/amazon-linux/recommended:region=test-region': '{"image_id": "ami-1234"}', + // eslint-disable-next-line max-len + 'ami:account=12345678:filters.image-type.0=machine:filters.name.0=amzn-ami-vpc-nat-*:filters.state.0=available:owners.0=amazon:region=test-region': 'ami-1234', + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': { + vpcId: 'vpc-60900905', + subnetGroups: [ + { + type: 'Public', + name: 'Public', + subnets: [ + { + subnetId: 'subnet-e19455ca', + availabilityZone: 'us-east-1a', + routeTableId: 'rtb-e19455ca', + }, + { + subnetId: 'subnet-e0c24797', + availabilityZone: 'us-east-1b', + routeTableId: 'rtb-e0c24797', + }, + { + subnetId: 'subnet-ccd77395', + availabilityZone: 'us-east-1c', + routeTableId: 'rtb-ccd77395', + }, + ], + }, + ], + }, + }, + env: { + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + CDK_INTEG_HOSTED_ZONE_ID: 'Z23ABC4XYZL05B', + CDK_INTEG_HOSTED_ZONE_NAME: 'example.com', + CDK_INTEG_DOMAIN_NAME: '*.example.com', + CDK_INTEG_CERT_ARN: 'arn:aws:acm:test-region:12345678:certificate/86468209-a272-595d-b831-0efb6421265z', + CDK_INTEG_SUBNET_ID: 'subnet-0dff1a399d8f6f92c', + }, +}; + +/** + * Return the currently recommended flags for `aws-cdk-lib`. + * + * These have been built into the CLI at build time. If this ever gets changed + * back to a dynamic load, remember that this source file may be bundled into + * a JavaScript bundle, and `__dirname` might not point where you think it does. + */ +export function currentlyRecommendedAwsCdkLibFlags() { + return recommendedFlagsFile; +} diff --git a/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts b/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts new file mode 100644 index 000000000..f5d90caa4 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts @@ -0,0 +1,383 @@ +import * as path from 'path'; +import type { WritableOptions } from 'stream'; +import { Writable } from 'stream'; +import { StringDecoder } from 'string_decoder'; +import type { ResourceDifference } from '@aws-cdk/cloudformation-diff'; +import { fullDiff, formatDifferences, ResourceImpact } from '@aws-cdk/cloudformation-diff'; +import { AssemblyManifestReader } from './private/cloud-assembly'; +import type { IntegRunnerOptions } from './runner-base'; +import { IntegRunner, DEFAULT_SYNTH_OPTIONS } from './runner-base'; +import type { Diagnostic, DestructiveChange, SnapshotVerificationOptions } from '../workers/common'; +import { DiagnosticReason } from '../workers/common'; + +interface SnapshotAssembly { + /** + * Map of stacks that are part of this assembly + */ + [stackName: string]: { + /** + * All templates for this stack, including nested stacks + */ + templates: { + [templateId: string]: any; + }; + + /** + * List of asset Ids that are used by this assembly + */ + assets: string[]; + }; +} + +/** + * Runner for snapshot tests. This handles orchestrating + * the validation of the integration test snapshots + */ +export class IntegSnapshotRunner extends IntegRunner { + constructor(options: IntegRunnerOptions) { + super(options); + } + + /** + * Synth the integration tests and compare the templates + * to the existing snapshot. + * + * @returns any diagnostics and any destructive changes + */ + public testSnapshot(options: SnapshotVerificationOptions = {}): { diagnostics: Diagnostic[]; destructiveChanges: DestructiveChange[] } { + let doClean = true; + try { + const expectedSnapshotAssembly = this.getSnapshotAssembly(this.snapshotDir, this.expectedTestSuite?.stacks); + + // synth the integration test + // FIXME: ideally we should not need to run this again if + // the cdkOutDir exists already, but for some reason generateActualSnapshot + // generates an incorrect snapshot and I have no idea why so synth again here + // to produce the "correct" snapshot + const env = { + ...DEFAULT_SYNTH_OPTIONS.env, + CDK_CONTEXT_JSON: JSON.stringify(this.getContext({ + ...this.actualTestSuite.enableLookups ? DEFAULT_SYNTH_OPTIONS.context : {}, + })), + }; + this.cdk.synthFast({ + execCmd: this.cdkApp.split(' '), + env, + output: path.relative(this.directory, this.cdkOutDir), + }); + + // read the "actual" snapshot + const actualSnapshotAssembly = this.getSnapshotAssembly(this.cdkOutDir, this.actualTestSuite.stacks); + + // diff the existing snapshot (expected) with the integration test (actual) + const diagnostics = this.diffAssembly(expectedSnapshotAssembly, actualSnapshotAssembly); + + if (diagnostics.diagnostics.length) { + // Attach additional messages to the first diagnostic + const additionalMessages: string[] = []; + + if (options.retain) { + additionalMessages.push( + `(Failure retained) Expected: ${path.relative(process.cwd(), this.snapshotDir)}`, + ` Actual: ${path.relative(process.cwd(), this.cdkOutDir)}`, + ), + doClean = false; + } + + if (options.verbose) { + // Show the command necessary to repro this + const envSet = Object.entries(env) + .filter(([k, _]) => k !== 'CDK_CONTEXT_JSON') + .map(([k, v]) => `${k}='${v}'`); + const envCmd = envSet.length > 0 ? ['env', ...envSet] : []; + + additionalMessages.push( + 'Repro:', + ` ${[...envCmd, 'cdk synth', `-a '${this.cdkApp}'`, `-o '${this.cdkOutDir}'`, ...Object.entries(this.getContext()).flatMap(([k, v]) => typeof v !== 'object' ? [`-c '${k}=${v}'`] : [])].join(' ')}`, + + ); + } + + diagnostics.diagnostics[0] = { + ...diagnostics.diagnostics[0], + additionalMessages, + }; + } + + return diagnostics; + } catch (e) { + throw e; + } finally { + if (doClean) { + this.cleanup(); + } + } + } + + /** + * For a given cloud assembly return a collection of all templates + * that should be part of the snapshot and any required meta data. + * + * @param cloudAssemblyDir The directory of the cloud assembly to look for snapshots + * @param pickStacks Pick only these stacks from the cloud assembly + * @returns A SnapshotAssembly, the collection of all templates in this snapshot and required meta data + */ + private getSnapshotAssembly(cloudAssemblyDir: string, pickStacks: string[] = []): SnapshotAssembly { + const assembly = this.readAssembly(cloudAssemblyDir); + const stacks = assembly.stacks; + const snapshots: SnapshotAssembly = {}; + for (const [stackName, stackTemplate] of Object.entries(stacks)) { + if (pickStacks.includes(stackName)) { + const manifest = AssemblyManifestReader.fromPath(cloudAssemblyDir); + const assets = manifest.getAssetIdsForStack(stackName); + + snapshots[stackName] = { + templates: { + [stackName]: stackTemplate, + ...assembly.getNestedStacksForStack(stackName), + }, + assets, + }; + } + } + + return snapshots; + } + + /** + * For a given stack return all resource types that are allowed to be destroyed + * as part of a stack update + * + * @param stackId the stack id + * @returns a list of resource types or undefined if none are found + */ + private getAllowedDestroyTypesForStack(stackId: string): string[] | undefined { + for (const testCase of Object.values(this.actualTests() ?? {})) { + if (testCase.stacks.includes(stackId)) { + return testCase.allowDestroy; + } + } + return undefined; + } + + /** + * Find any differences between the existing and expected snapshots + * + * @param existing - the existing (expected) snapshot + * @param actual - the new (actual) snapshot + * @returns any diagnostics and any destructive changes + */ + private diffAssembly( + expected: SnapshotAssembly, + actual: SnapshotAssembly, + ): { diagnostics: Diagnostic[]; destructiveChanges: DestructiveChange[] } { + const failures: Diagnostic[] = []; + const destructiveChanges: DestructiveChange[] = []; + + // check if there is a CFN template in the current snapshot + // that does not exist in the "actual" snapshot + for (const [stackId, stack] of Object.entries(expected)) { + for (const templateId of Object.keys(stack.templates)) { + if (!actual[stackId]?.templates[templateId]) { + failures.push({ + testName: this.testName, + stackName: templateId, + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: `${templateId} exists in snapshot, but not in actual`, + }); + } + } + } + + for (const [stackId, stack] of Object.entries(actual)) { + for (const templateId of Object.keys(stack.templates)) { + // check if there is a CFN template in the "actual" snapshot + // that does not exist in the current snapshot + if (!expected[stackId]?.templates[templateId]) { + failures.push({ + testName: this.testName, + stackName: templateId, + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: `${templateId} does not exist in snapshot, but does in actual`, + }); + continue; + } else { + const config = { + diffAssets: this.actualTestSuite.getOptionsForStack(stackId)?.diffAssets, + }; + let actualTemplate = actual[stackId].templates[templateId]; + let expectedTemplate = expected[stackId].templates[templateId]; + + // if we are not verifying asset hashes then remove the specific + // asset hashes from the templates so they are not part of the diff + // comparison + if (!config.diffAssets) { + actualTemplate = this.canonicalizeTemplate(actualTemplate, actual[stackId].assets); + expectedTemplate = this.canonicalizeTemplate(expectedTemplate, expected[stackId].assets); + } + const templateDiff = fullDiff(expectedTemplate, actualTemplate); + if (!templateDiff.isEmpty) { + const allowedDestroyTypes = this.getAllowedDestroyTypesForStack(stackId) ?? []; + + // go through all the resource differences and check for any + // "destructive" changes + templateDiff.resources.forEachDifference((logicalId: string, change: ResourceDifference) => { + // if the change is a removal it will not show up as a 'changeImpact' + // so need to check for it separately, unless it is a resourceType that + // has been "allowed" to be destroyed + const resourceType = change.oldValue?.Type ?? change.newValue?.Type; + if (resourceType && allowedDestroyTypes.includes(resourceType)) { + return; + } + if (change.isRemoval) { + destructiveChanges.push({ + impact: ResourceImpact.WILL_DESTROY, + logicalId, + stackName: templateId, + }); + } else { + switch (change.changeImpact) { + case ResourceImpact.MAY_REPLACE: + case ResourceImpact.WILL_ORPHAN: + case ResourceImpact.WILL_DESTROY: + case ResourceImpact.WILL_REPLACE: + destructiveChanges.push({ + impact: change.changeImpact, + logicalId, + stackName: templateId, + }); + break; + } + } + }); + const writable = new StringWritable({}); + formatDifferences(writable, templateDiff); + failures.push({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + message: writable.data, + stackName: templateId, + testName: this.testName, + config, + }); + } + } + } + } + + return { + diagnostics: failures, + destructiveChanges, + }; + } + + private readAssembly(dir: string): AssemblyManifestReader { + return AssemblyManifestReader.fromPath(dir); + } + + /** + * Reduce template to a normal form where asset references have been normalized + * + * This makes it possible to compare templates if all that's different between + * them is the hashes of the asset values. + */ + private canonicalizeTemplate(template: any, assets: string[]): any { + const assetsSeen = new Set(); + const stringSubstitutions = new Array<[RegExp, string]>(); + + // Find assets via parameters (for LegacyStackSynthesizer) + const paramRe = /^AssetParameters([a-zA-Z0-9]{64})(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})$/; + for (const paramName of Object.keys(template?.Parameters || {})) { + const m = paramRe.exec(paramName); + if (!m) { + continue; + } + if (assetsSeen.has(m[1])) { + continue; + } + + assetsSeen.add(m[1]); + const ix = assetsSeen.size; + + // Full parameter reference + stringSubstitutions.push([ + new RegExp(`AssetParameters${m[1]}(S3Bucket|S3VersionKey|ArtifactHash)([a-zA-Z0-9]{8})`), + `Asset${ix}$1`, + ]); + // Substring asset hash reference + stringSubstitutions.push([ + new RegExp(`${m[1]}`), + `Asset${ix}Hash`, + ]); + } + + // find assets defined in the asset manifest + try { + assets.forEach(asset => { + if (!assetsSeen.has(asset)) { + assetsSeen.add(asset); + const ix = assetsSeen.size; + stringSubstitutions.push([ + new RegExp(asset), + `Asset${ix}$1`, + ]); + } + }); + } catch { + // if there is no asset manifest that is fine. + } + + // Substitute them out + return substitute(template); + + function substitute(what: any): any { + if (Array.isArray(what)) { + return what.map(substitute); + } + + if (typeof what === 'object' && what !== null) { + const ret: any = {}; + for (const [k, v] of Object.entries(what)) { + ret[stringSub(k)] = substitute(v); + } + return ret; + } + + if (typeof what === 'string') { + return stringSub(what); + } + + return what; + } + + function stringSub(x: string) { + for (const [re, replacement] of stringSubstitutions) { + x = x.replace(re, replacement); + } + return x; + } + } +} + +class StringWritable extends Writable { + public data: string; + private _decoder: StringDecoder; + constructor(options: WritableOptions) { + super(options); + this._decoder = new StringDecoder(); + this.data = ''; + } + + _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void { + if (encoding === 'buffer') { + chunk = this._decoder.write(chunk); + } + + this.data += chunk; + callback(); + } + + _final(callback: (error?: Error | null) => void): void { + this.data += this._decoder.end(); + callback(); + } +} diff --git a/packages/@aws-cdk/integ-runner/lib/utils.ts b/packages/@aws-cdk/integ-runner/lib/utils.ts new file mode 100644 index 000000000..14b8e03c9 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/utils.ts @@ -0,0 +1,110 @@ +// Helper functions for CDK Exec +import { spawnSync } from 'child_process'; + +/** + * Our own execute function which doesn't use shells and strings. + */ +export function exec(commandLine: string[], options: { cwd?: string; verbose?: boolean; env?: any } = { }): any { + const proc = spawnSync(commandLine[0], commandLine.slice(1), { + stdio: ['ignore', 'pipe', options.verbose ? 'inherit' : 'pipe'], // inherit STDERR in verbose mode + env: { + ...process.env, + ...options.env, + }, + cwd: options.cwd, + }); + + if (proc.error) { + throw proc.error; + } + if (proc.status !== 0) { + if (process.stderr) { // will be 'null' in verbose mode + process.stderr.write(proc.stderr); + } + throw new Error(`Command exited with ${proc.status ? `status ${proc.status}` : `signal ${proc.signal}`}`); + } + + const output = proc.stdout.toString('utf-8').trim(); + + return output; +} + +/** + * Flatten a list of lists into a list of elements + */ +export function flatten(xs: T[][]): T[] { + return Array.prototype.concat.apply([], xs); +} + +/** + * Chain commands + */ +export function chain(commands: string[]): string { + return commands.filter(c => !!c).join(' && '); +} + +/** + * Split command to chunks by space + */ +export function chunks(command: string): string[] { + const result = command.match(/(?:[^\s"]+|"[^"]*")+/g); + return result ?? []; +} + +/** + * A class holding a set of items which are being crossed off in time + * + * If it takes too long to cross off a new item, print the list. + */ +export class WorkList { + private readonly remaining = new Set(this.items); + private readonly timeout: number; + private timer?: NodeJS.Timeout; + + constructor(private readonly items: A[], private readonly options: WorkListOptions = {}) { + this.timeout = options.timeout ?? 60_000; + this.scheduleTimer(); + } + + public crossOff(item: A) { + this.remaining.delete(item); + this.stopTimer(); + if (this.remaining.size > 0) { + this.scheduleTimer(); + } + } + + public done() { + this.remaining.clear(); + this.stopTimer(); + } + + private stopTimer() { + if (this.timer) { + clearTimeout(this.timer); + this.timer = undefined; + } + } + + private scheduleTimer() { + this.timer = setTimeout(() => this.report(), this.timeout); + } + + private report() { + this.options.onTimeout?.(this.remaining); + } +} + +export interface WorkListOptions { + /** + * When to reply with remaining items + * + * @default 60000 + */ + readonly timeout?: number; + + /** + * Function to call when timeout hits + */ + readonly onTimeout?: (x: Set) => void; +} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/common.ts b/packages/@aws-cdk/integ-runner/lib/workers/common.ts new file mode 100644 index 000000000..e3555e60d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/common.ts @@ -0,0 +1,320 @@ +import { format } from 'util'; +import type { ResourceImpact } from '@aws-cdk/cloudformation-diff'; +import * as chalk from 'chalk'; +import * as logger from '../logger'; +import type { IntegTestInfo } from '../runner/integration-tests'; + +/** + * The aggregate results from running assertions on a test case + */ +export type AssertionResults = { [id: string]: AssertionResult }; + +/** + * The result of an individual assertion + */ +export interface AssertionResult { + /** + * The assertion message. If the assertion failed, this will + * include the reason. + */ + readonly message: string; + + /** + * Whether the assertion succeeded or failed + */ + readonly status: 'success' | 'fail'; +} + +/** + * Config for an integration test + */ +export interface IntegTestWorkerConfig extends IntegTestInfo { + /** + * A list of any destructive changes + * + * @default [] + */ + readonly destructiveChanges?: DestructiveChange[]; +} + +/** + * Information on any destructive changes + */ +export interface DestructiveChange { + /** + * The logicalId of the resource with a destructive change + */ + readonly logicalId: string; + + /** + * The name of the stack that contains the destructive change + */ + readonly stackName: string; + + /** + * The impact of the destructive change + */ + readonly impact: ResourceImpact; +} + +/** + * Represents integration tests metrics for a given worker + */ +export interface IntegRunnerMetrics { + /** + * The region the test was run in + */ + readonly region: string; + + /** + * The total duration of the worker. + * This will be the sum of all individual test durations + */ + readonly duration: number; + + /** + * Contains the duration of individual tests that the + * worker executed. + * + * Map of testName to duration. + */ + readonly tests: { [testName: string]: number }; + + /** + * The profile that was used to run the test + * + * @default - default profile + */ + readonly profile?: string; +} + +export interface SnapshotVerificationOptions { + /** + * Retain failed snapshot comparisons + * + * @default false + */ + readonly retain?: boolean; + + /** + * Verbose mode + * + * @default false + */ + readonly verbose?: boolean; +} + +/** + * Integration test results + */ +export interface IntegBatchResponse { + /** + * List of failed tests + */ + readonly failedTests: IntegTestInfo[]; + + /** + * List of Integration test metrics. Each entry in the + * list represents metrics from a single worker (account + region). + */ + readonly metrics: IntegRunnerMetrics[]; +} + +/** + * Common options for running integration tests + */ +export interface IntegTestOptions { + /** + * A list of integration tests to run + * in this batch + */ + readonly tests: IntegTestWorkerConfig[]; + + /** + * Whether or not to destroy the stacks at the + * end of the test + * + * @default true + */ + readonly clean?: boolean; + + /** + * When this is set to `true` the snapshot will + * be created _without_ running the integration test + * The resulting snapshot SHOULD NOT be checked in + * + * @default false + */ + readonly dryRun?: boolean; + + /** + * The level of verbosity for logging. + * Higher number means more output. + * + * @default 0 + */ + readonly verbosity?: number; + + /** + * If this is set to true then the stack update workflow will be disabled + * + * @default true + */ + readonly updateWorkflow?: boolean; + + /** + * true if running in watch mode + * + * @default false + */ + readonly watch?: boolean; +} + +/** + * Represents possible reasons for a diagnostic + */ +export enum DiagnosticReason { + /** + * The integration test failed because there + * is not existing snapshot + */ + NO_SNAPSHOT = 'NO_SNAPSHOT', + + /** + * The integration test failed + */ + TEST_FAILED = 'TEST_FAILED', + + /** + * There was an error running the integration test + */ + TEST_ERROR = 'TEST_ERROR', + + /** + * The snapshot test failed because the actual + * snapshot was different than the expected snapshot + */ + SNAPSHOT_FAILED = 'SNAPSHOT_FAILED', + + /** + * The snapshot test failed because there was an error executing it + */ + SNAPSHOT_ERROR = 'SNAPSHOT_ERROR', + + /** + * The snapshot test succeeded + */ + SNAPSHOT_SUCCESS = 'SNAPSHOT_SUCCESS', + + /** + * The integration test succeeded + */ + TEST_SUCCESS = 'TEST_SUCCESS', + + /** + * The assertion failed + */ + ASSERTION_FAILED = 'ASSERTION_FAILED', +} + +/** + * Integration test diagnostics + * This is used to report back the status of each test + */ +export interface Diagnostic { + /** + * The name of the test + */ + readonly testName: string; + + /** + * The name of the stack + */ + readonly stackName: string; + + /** + * The diagnostic message + */ + readonly message: string; + + /** + * The time it took to run the test + */ + readonly duration?: number; + + /** + * The reason for the diagnostic + */ + readonly reason: DiagnosticReason; + + /** + * Additional messages to print + */ + readonly additionalMessages?: string[]; + + /** + * Relevant config options that were used for the integ test + */ + readonly config?: Record; +} + +export function printSummary(total: number, failed: number): void { + if (failed > 0) { + logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.red(failed), chalk.red('failed'), total); + } else { + logger.print('%s: %s %s, %s total', chalk.bold('Tests'), chalk.green(total), chalk.green('passed'), total); + } +} + +/** + * Format the assertion results so that the results can be + * printed + */ +export function formatAssertionResults(results: AssertionResults): string { + return Object.entries(results) + .map(([id, result]) => format('%s%s', id, result.status === 'success' ? ` - ${result.status}` : `\n${result.message}`)) + .join('\n '); +} + +/** + * Print out the results from tests + */ +export function printResults(diagnostic: Diagnostic): void { + switch (diagnostic.reason) { + case DiagnosticReason.SNAPSHOT_SUCCESS: + logger.success(' UNCHANGED %s %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`)); + break; + case DiagnosticReason.TEST_SUCCESS: + logger.success(' SUCCESS %s %s\n ', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`), diagnostic.message); + break; + case DiagnosticReason.NO_SNAPSHOT: + logger.error(' NEW %s %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`)); + break; + case DiagnosticReason.SNAPSHOT_FAILED: + logger.error(' CHANGED %s %s\n %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`), diagnostic.message); + break; + case DiagnosticReason.SNAPSHOT_ERROR: + case DiagnosticReason.TEST_ERROR: + logger.error(' ERROR %s %s\n %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`), diagnostic.message); + break; + case DiagnosticReason.TEST_FAILED: + logger.error(' FAILED %s %s\n %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`), diagnostic.message); + break; + case DiagnosticReason.ASSERTION_FAILED: + logger.error(' ASSERT %s %s\n %s', diagnostic.testName, chalk.gray(`${diagnostic.duration}s`), diagnostic.message); + break; + } + for (const addl of diagnostic.additionalMessages ?? []) { + logger.print(` ${addl}`); + } +} + +export function printLaggards(testNames: Set) { + const parts = [ + ' ', + `Waiting for ${testNames.size} more`, + testNames.size < 10 ? ['(', Array.from(testNames).join(', '), ')'].join('') : '', + ]; + + logger.print(chalk.grey(parts.filter(x => x).join(' '))); +} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts new file mode 100644 index 000000000..8f92b9dd0 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/extract/extract_worker.ts @@ -0,0 +1,189 @@ +import * as workerpool from 'workerpool'; +import { IntegSnapshotRunner, IntegTestRunner } from '../../runner'; +import type { IntegTestInfo } from '../../runner/integration-tests'; +import { IntegTest } from '../../runner/integration-tests'; +import type { IntegTestWorkerConfig, SnapshotVerificationOptions, Diagnostic } from '../common'; +import { DiagnosticReason, formatAssertionResults } from '../common'; +import type { IntegTestBatchRequest } from '../integ-test-worker'; +import type { IntegWatchOptions } from '../integ-watch-worker'; + +/** + * Runs a single integration test batch request. + * If the test does not have an existing snapshot, + * this will first generate a snapshot and then execute + * the integration tests. + * + * If the tests succeed it will then save the snapshot + */ +export function integTestWorker(request: IntegTestBatchRequest): IntegTestWorkerConfig[] { + const failures: IntegTestInfo[] = []; + const verbosity = request.verbosity ?? 0; + + for (const testInfo of request.tests) { + const test = new IntegTest({ + ...testInfo, + watch: request.watch, + }); // Hydrate from data + const start = Date.now(); + + try { + const runner = new IntegTestRunner({ + test, + profile: request.profile, + env: { + AWS_REGION: request.region, + CDK_DOCKER: process.env.CDK_DOCKER ?? 'docker', + }, + showOutput: verbosity >= 2, + }, testInfo.destructiveChanges); + + const tests = runner.actualTests(); + + if (!tests || Object.keys(tests).length === 0) { + throw new Error(`No tests defined for ${runner.testName}`); + } + for (const testCaseName of Object.keys(tests)) { + try { + const results = runner.runIntegTestCase({ + testCaseName, + clean: request.clean, + dryRun: request.dryRun, + updateWorkflow: request.updateWorkflow, + verbosity, + }); + if (results && Object.values(results).some(result => result.status === 'fail')) { + failures.push(testInfo); + workerpool.workerEmit({ + reason: DiagnosticReason.ASSERTION_FAILED, + testName: `${runner.testName}-${testCaseName} (${request.profile}/${request.region})`, + message: formatAssertionResults(results), + duration: (Date.now() - start) / 1000, + }); + } else { + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_SUCCESS, + testName: `${runner.testName}-${testCaseName}`, + message: results ? formatAssertionResults(results) : 'NO ASSERTIONS', + duration: (Date.now() - start) / 1000, + }); + } + } catch (e) { + failures.push(testInfo); + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_FAILED, + testName: `${runner.testName}-${testCaseName} (${request.profile}/${request.region})`, + message: `Integration test failed: ${e}`, + duration: (Date.now() - start) / 1000, + }); + } + } + } catch (e) { + failures.push(testInfo); + workerpool.workerEmit({ + reason: DiagnosticReason.TEST_ERROR, + testName: `${testInfo.fileName} (${request.profile}/${request.region})`, + message: `Error during integration test: ${e}`, + duration: (Date.now() - start) / 1000, + }); + } + } + + return failures; +} + +export async function watchTestWorker(options: IntegWatchOptions) { + const verbosity = options.verbosity ?? 0; + const test = new IntegTest(options); + const runner = new IntegTestRunner({ + test, + profile: options.profile, + env: { + AWS_REGION: options.region, + CDK_DOCKER: process.env.CDK_DOCKER ?? 'docker', + }, + showOutput: verbosity >= 2, + }); + runner.createCdkContextJson(); + const tests = runner.actualTests(); + + if (!tests || Object.keys(tests).length === 0) { + throw new Error(`No tests defined for ${runner.testName}`); + } + for (const testCaseName of Object.keys(tests)) { + await runner.watchIntegTest({ + testCaseName, + verbosity, + }); + } +} + +/** + * Runs a single snapshot test batch request. + * For each integration test this will check to see + * if there is an existing snapshot, and if there is will + * check if there are any changes + */ +export function snapshotTestWorker(testInfo: IntegTestInfo, options: SnapshotVerificationOptions = {}): IntegTestWorkerConfig[] { + const failedTests = new Array(); + const start = Date.now(); + const test = new IntegTest(testInfo); // Hydrate the data record again + + const timer = setTimeout(() => { + workerpool.workerEmit({ + reason: DiagnosticReason.SNAPSHOT_ERROR, + testName: test.testName, + message: 'Test is taking a very long time', + duration: (Date.now() - start) / 1000, + }); + }, 60_000); + + try { + const runner = new IntegSnapshotRunner({ test }); + if (!runner.hasSnapshot()) { + workerpool.workerEmit({ + reason: DiagnosticReason.NO_SNAPSHOT, + testName: test.testName, + message: 'No Snapshot', + duration: (Date.now() - start) / 1000, + }); + failedTests.push(test.info); + } else { + const { diagnostics, destructiveChanges } = runner.testSnapshot(options); + if (diagnostics.length > 0) { + diagnostics.forEach(diagnostic => workerpool.workerEmit({ + ...diagnostic, + duration: (Date.now() - start) / 1000, + } as Diagnostic)); + failedTests.push({ + ...test.info, + destructiveChanges, + }); + } else { + workerpool.workerEmit({ + reason: DiagnosticReason.SNAPSHOT_SUCCESS, + testName: test.testName, + message: 'Success', + duration: (Date.now() - start) / 1000, + } as Diagnostic); + } + } + } catch (e: any) { + failedTests.push(test.info); + workerpool.workerEmit({ + message: e.message, + testName: test.testName, + reason: DiagnosticReason.SNAPSHOT_ERROR, + duration: (Date.now() - start) / 1000, + } as Diagnostic); + } finally { + clearTimeout(timer); + } + + return failedTests; +} + +workerpool.worker({ + snapshotTestWorker, + integTestWorker, + watchTestWorker, +}); diff --git a/packages/@aws-cdk/integ-runner/lib/workers/extract/index.ts b/packages/@aws-cdk/integ-runner/lib/workers/extract/index.ts new file mode 100644 index 000000000..f1a721136 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/extract/index.ts @@ -0,0 +1 @@ +export * from './extract_worker'; diff --git a/packages/@aws-cdk/integ-runner/lib/workers/index.ts b/packages/@aws-cdk/integ-runner/lib/workers/index.ts new file mode 100644 index 000000000..f42509004 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/index.ts @@ -0,0 +1,3 @@ +export * from './common'; +export * from './integ-test-worker'; +export * from './integ-snapshot-worker'; diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts new file mode 100644 index 000000000..ac418c15f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-snapshot-worker.ts @@ -0,0 +1,40 @@ +import type * as workerpool from 'workerpool'; +import type { IntegTestWorkerConfig, SnapshotVerificationOptions } from './common'; +import { printSummary, printResults, printLaggards } from './common'; +import * as logger from '../logger'; +import type { IntegTest } from '../runner/integration-tests'; +import { flatten, WorkList } from '../utils'; + +/** + * Run Snapshot tests + * First batch up the tests. By default there will be 3 tests per batch. + * Use a workerpool to run the batches in parallel. + */ +export async function runSnapshotTests( + pool: workerpool.WorkerPool, + tests: IntegTest[], + options: SnapshotVerificationOptions, +): Promise { + logger.highlight('\nVerifying integration test snapshots...\n'); + + const todo = new WorkList(tests.map(t => t.testName), { + onTimeout: printLaggards, + }); + + // The worker pool is already limited + // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism + const failedTests: IntegTestWorkerConfig[][] = await Promise.all( + tests.map((test) => pool.exec('snapshotTestWorker', [test.info /* Dehydrate class -> data */, options], { + on: (x) => { + todo.crossOff(x.testName); + printResults(x); + }, + })), + ); + todo.done(); + const testsToRun = flatten(failedTests); + + logger.highlight('\nSnapshot Results: \n'); + printSummary(tests.length, testsToRun.length); + return testsToRun; +} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts new file mode 100644 index 000000000..f27e57048 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-test-worker.ts @@ -0,0 +1,162 @@ +import type * as workerpool from 'workerpool'; +import type { IntegBatchResponse, IntegTestOptions, IntegRunnerMetrics } from './common'; +import { printResults, printSummary } from './common'; +import * as logger from '../logger'; +import type { IntegTestInfo } from '../runner/integration-tests'; +import { flatten } from '../utils'; + +/** + * Options for an integration test batch + */ +export interface IntegTestBatchRequest extends IntegTestOptions { + /** + * The AWS region to run this batch in + */ + readonly region: string; + + /** + * The AWS profile to use when running this test + */ + readonly profile?: string; +} + +/** + * Options for running all integration tests + */ +export interface IntegTestRunOptions extends IntegTestOptions { + /** + * The regions to run the integration tests across. + * This allows the runner to run integration tests in parallel + */ + readonly regions: string[]; + + /** + * List of AWS profiles. This will be used in conjunction with `regions` + * to run tests in parallel across accounts + regions + */ + readonly profiles?: string[]; + + /** + * The workerpool to use + */ + readonly pool: workerpool.WorkerPool; +} + +/** + * Run Integration tests. + */ +export async function runIntegrationTests(options: IntegTestRunOptions): Promise<{ success: boolean; metrics: IntegRunnerMetrics[] }> { + logger.highlight('\nRunning integration tests for failed tests...\n'); + logger.print( + 'Running in parallel across %sregions: %s', + options.profiles ? `profiles ${options.profiles.join(', ')} and `: '', + options.regions.join(', ')); + const totalTests = options.tests.length; + + const responses = await runIntegrationTestsInParallel(options); + logger.highlight('\nTest Results: \n'); + printSummary(totalTests, responses.failedTests.length); + return { + success: responses.failedTests.length === 0, + metrics: responses.metrics, + }; +} + +/** + * Represents a worker for a single account + region + */ +interface AccountWorker { + /** + * The region the worker should run in + */ + readonly region: string; + + /** + * The AWS profile that the worker should use + * This will be passed as the '--profile' option to the CDK CLI + * + * @default - default profile + */ + readonly profile?: string; +} + +/** + * Returns a list of AccountWorkers based on the list of regions and profiles + * given to the CLI. + */ +function getAccountWorkers(regions: string[], profiles?: string[]): AccountWorker[] { + const workers: AccountWorker[] = []; + function pushWorker(profile?: string) { + for (const region of regions) { + workers.push({ + region, + profile, + }); + } + } + if (profiles && profiles.length > 0) { + for (const profile of profiles ?? []) { + pushWorker(profile); + } + } else { + pushWorker(); + } + return workers; +} + +/** + * Runs a set of integration tests in parallel across a list of AWS regions. + * Only a single test can be run at a time in a given region. Once a region + * is done running a test, the next test will be pulled from the queue + */ +export async function runIntegrationTestsInParallel( + options: IntegTestRunOptions, +): Promise { + const queue = options.tests; + const results: IntegBatchResponse = { + metrics: [], + failedTests: [], + }; + const accountWorkers: AccountWorker[] = getAccountWorkers(options.regions, options.profiles); + + async function runTest(worker: AccountWorker): Promise { + const start = Date.now(); + const tests: { [testName: string]: number } = {}; + do { + const test = queue.pop(); + if (!test) break; + const testStart = Date.now(); + logger.highlight(`Running test ${test.fileName} in ${worker.profile ? worker.profile + '/' : ''}${worker.region}`); + const response: IntegTestInfo[][] = await options.pool.exec('integTestWorker', [{ + watch: options.watch, + region: worker.region, + profile: worker.profile, + tests: [test], + clean: options.clean, + dryRun: options.dryRun, + verbosity: options.verbosity, + updateWorkflow: options.updateWorkflow, + }], { + on: printResults, + }); + + results.failedTests.push(...flatten(response)); + tests[test.fileName] = (Date.now() - testStart) / 1000; + } while (queue.length > 0); + const metrics: IntegRunnerMetrics = { + region: worker.region, + profile: worker.profile, + duration: (Date.now() - start) / 1000, + tests, + }; + if (Object.keys(tests).length > 0) { + results.metrics.push(metrics); + } + } + + const workers = accountWorkers.map((worker) => runTest(worker)); + // Workers are their own concurrency limits + // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism + await Promise.all(workers); + return results; +} diff --git a/packages/@aws-cdk/integ-runner/lib/workers/integ-watch-worker.ts b/packages/@aws-cdk/integ-runner/lib/workers/integ-watch-worker.ts new file mode 100644 index 000000000..e6c88074b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/lib/workers/integ-watch-worker.ts @@ -0,0 +1,14 @@ +import type * as workerpool from 'workerpool'; +import { printResults } from './common'; +import type { IntegTestInfo } from '../runner'; + +export interface IntegWatchOptions extends IntegTestInfo { + readonly region: string; + readonly profile?: string; + readonly verbosity?: number; +} +export async function watchIntegrationTest(pool: workerpool.WorkerPool, options: IntegWatchOptions): Promise { + await pool.exec('watchTestWorker', [options], { + on: printResults, + }); +} diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json new file mode 100644 index 000000000..a42858cc2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/package.json @@ -0,0 +1,98 @@ +{ + "name": "@aws-cdk/integ-runner", + "description": "CDK Integration Testing Tool", + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk-cli", + "directory": "packages/@aws-cdk/integ-runner" + }, + "bin": { + "integ-runner": "bin/integ-runner" + }, + "scripts": { + "build": "npx projen build", + "bump": "npx projen bump", + "check-for-updates": "npx projen check-for-updates", + "check-licenses": "npx projen check-licenses", + "compile": "npx projen compile", + "default": "npx projen default", + "eslint": "npx projen eslint", + "gather-versions": "npx projen gather-versions", + "nx": "npx projen nx", + "package": "npx projen package", + "post-compile": "npx projen post-compile", + "pre-compile": "npx projen pre-compile", + "test": "npx projen test", + "test:watch": "npx projen test:watch", + "unbump": "npx projen unbump", + "watch": "npx projen watch", + "projen": "npx projen" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "devDependencies": { + "@aws-cdk/integ-tests-alpha": "2.184.1-alpha.0", + "@cdklabs/eslint-plugin": "^1.3.2", + "@stylistic/eslint-plugin": "^3", + "@types/fs-extra": "^11.0.4", + "@types/jest": "^29.5.14", + "@types/mock-fs": "^4", + "@types/node": "^16", + "@types/workerpool": "^6", + "@types/yargs": "^17.0.33", + "@typescript-eslint/eslint-plugin": "^8", + "@typescript-eslint/parser": "^8", + "aws-cdk-lib": "^2.184.1", + "commit-and-tag-version": "^12", + "constructs": "^10", + "eslint": "^9", + "eslint-config-prettier": "^10.1.1", + "eslint-import-resolver-typescript": "^4.2.1", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jest": "^28.11.0", + "eslint-plugin-jsdoc": "^50.6.8", + "eslint-plugin-prettier": "^5.2.3", + "jest": "^29.7.0", + "jest-junit": "^16", + "license-checker": "^25.0.1", + "mock-fs": "^5", + "prettier": "^2.8", + "projen": "^0.91.18", + "ts-jest": "^29.2.6", + "typescript": "5.6" + }, + "dependencies": { + "@aws-cdk/aws-service-spec": "^0.1.62", + "@aws-cdk/cdk-cli-wrapper": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/cloudformation-diff": "0.0.0", + "@aws-cdk/cx-api": "^2.184.1", + "@aws-sdk/client-cloudformation": "^3", + "aws-cdk": "0.0.0", + "cdk-assets": "0.0.0", + "chalk": "^4", + "chokidar": "^3", + "fs-extra": "^9", + "workerpool": "^6", + "yargs": "^16" + }, + "keywords": [ + "aws", + "cdk" + ], + "engines": { + "node": ">= 14.15.0" + }, + "main": "lib/index.js", + "license": "Apache-2.0", + "homepage": "https://github.com/aws/aws-cdk", + "publishConfig": { + "access": "public" + }, + "version": "0.0.0", + "types": "lib/index.d.ts", + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/@aws-cdk/integ-runner/test/cli.test.ts b/packages/@aws-cdk/integ-runner/test/cli.test.ts new file mode 100644 index 000000000..7f052bca0 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/cli.test.ts @@ -0,0 +1,167 @@ +import * as fs from 'fs'; +import * as os from 'os'; +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('Test discovery', () => { + const currentCwd = process.cwd(); + beforeAll(() => { + process.chdir(path.join(__dirname, '..')); + }); + afterAll(() => { + process.chdir(currentCwd); + }); + + test('find by default pattern', async () => { + await main(['--list', '--directory=test/test-data']); + + // Expect nothing to be found since this directory doesn't contain files with the default pattern + expect(stdoutMock.mock.calls).toEqual([['\n']]); + }); + + test('find by custom pattern', async () => { + await main(['--list', '--directory=test/test-data', '--language=javascript', '--test-regex="^xxxxx\.integ-test[12]\.js$"']); + + expect(stdoutMock.mock.calls).toEqual([[ + [ + 'xxxxx.integ-test1.js', + 'xxxxx.integ-test2.js', + '', + ].join('\n'), + ]]); + }); + + test('list only shows explicitly provided tests', async () => { + 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([[ + [ + 'xxxxx.integ-test1.js', + 'xxxxx.integ-test2.js', + '', + ].join('\n'), + ]]); + }); + + 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.toThrow('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.toThrow('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', () => { + const configFile = 'integ.config.json'; + const withConfig = (settings: any, fileName = configFile) => { + fs.writeFileSync(fileName, JSON.stringify(settings, null, 2), { encoding: 'utf-8' }); + }; + + const currentCwd = process.cwd(); + beforeEach(() => { + process.chdir(os.tmpdir()); + }); + afterEach(() => { + process.chdir(currentCwd); + }); + + test('options are read from config file', async () => { + // WHEN + withConfig({ + list: true, + maxWorkers: 3, + parallelRegions: [ + 'eu-west-1', + 'ap-southeast-2', + ], + }); + const options = parseCliArgs(); + + // THEN + expect(options.list).toBe(true); + expect(options.maxWorkers).toBe(3); + expect(options.testRegions).toEqual([ + 'eu-west-1', + 'ap-southeast-2', + ]); + }); + + test('cli options take precedent', async () => { + // WHEN + withConfig({ maxWorkers: 3 }); + const options = parseCliArgs(['--max-workers', '20']); + + // THEN + expect(options.maxWorkers).toBe(20); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/helpers.ts b/packages/@aws-cdk/integ-runner/test/helpers.ts new file mode 100644 index 000000000..88dc28502 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/helpers.ts @@ -0,0 +1,115 @@ +import type { ChildProcess } from 'child_process'; +import { Readable, Writable } from 'stream'; +import type { CdkCliWrapperOptions, DeployOptions, DestroyOptions, ICdk, ListOptions, SynthFastOptions, SynthOptions } from '@aws-cdk/cdk-cli-wrapper'; +import { CdkCliWrapper } from '@aws-cdk/cdk-cli-wrapper'; +import { IntegSnapshotRunner, IntegTest } from '../lib/runner'; +import type { DestructiveChange, Diagnostic } from '../lib/workers'; + +export interface MockCdkMocks { + deploy?: jest.MockedFn<(options: DeployOptions) => void>; + watch?: jest.MockedFn<(options: DeployOptions) => ChildProcess>; + synth?: jest.MockedFn<(options: SynthOptions) => void>; + synthFast?: jest.MockedFn<(options: SynthFastOptions) => void>; + destroy?: jest.MockedFn<(options: DestroyOptions) => void>; + list?: jest.MockedFn<(options: ListOptions) => string>; +} + +export class MockCdkProvider { + public readonly cdk: ICdk; + public readonly mocks: MockCdkMocks = {}; + + constructor(options: CdkCliWrapperOptions) { + this.cdk = new CdkCliWrapper(options); + } + + public mockDeploy(mock?: MockCdkMocks['deploy']) { + this.mocks.deploy = mock ?? jest.fn().mockImplementation(); + this.cdk.deploy = this.mocks.deploy; + } + public mockWatch(mock?: MockCdkMocks['watch']) { + this.mocks.watch = mock ?? jest.fn().mockImplementation(jest.fn(() => { + return { + on: (_event: 'close', listener: (..._args: any[]) => void) => { + listener(0); + }, + stdout: new Readable({ + read: jest.fn(() => { + }), + }), + stderr: new Readable({ + read: jest.fn(() => { + }), + }), + stdin: new Writable({ + write: jest.fn(() => { + }), + final: jest.fn(() => { + }), + }), + } as unknown as ChildProcess; + })); + this.cdk.watch = this.mocks.watch; + } + public mockSynth(mock?: MockCdkMocks['synth']) { + this.mocks.synth = mock ?? jest.fn().mockImplementation(); + this.cdk.synth = this.mocks.synth; + } + public mockSynthFast(mock?: MockCdkMocks['synthFast']) { + this.mocks.synthFast = mock ?? jest.fn().mockImplementation(); + this.cdk.synthFast = this.mocks.synthFast; + } + public mockDestroy(mock?: MockCdkMocks['destroy']) { + this.mocks.destroy = mock ?? jest.fn().mockImplementation(); + this.cdk.destroy = this.mocks.destroy; + } + public mockList(mock?: MockCdkMocks['list']) { + this.mocks.list = mock ?? jest.fn().mockImplementation(); + this.cdk.list = this.mocks.list; + } + public mockAll(mocks: MockCdkMocks = {}): Required { + this.mockDeploy(mocks.deploy); + this.mockWatch(mocks.watch); + this.mockSynth(mocks.synth); + this.mockSynthFast(mocks.synthFast); + this.mockDestroy(mocks.destroy); + this.mockList(mocks.list); + + return this.mocks as Required; + } + + /** + * Run a test of the testSnapshot method + * @param integTestFile This name is used to determined the expected (committed) snapshot + * @param actualSnapshot The directory of the snapshot that is used for of the actual (current) app + * @returns Diagnostics as they would be returned by testSnapshot + */ + public snapshotTest(integTestFile: string, actualSnapshot?: string): { + diagnostics: Diagnostic[]; + destructiveChanges: DestructiveChange[]; + } { + // WHEN + const integTest = new IntegSnapshotRunner({ + cdk: this.cdk, + test: new IntegTest({ + fileName: 'test/test-data/' + integTestFile, + discoveryRoot: 'test/test-data', + }), + integOutDir: actualSnapshot ? 'test/test-data/' + actualSnapshot : undefined, + }); + integTest.actualTests(); + const results = integTest.testSnapshot(); + + // THEN + expect(this.mocks.synthFast).toHaveBeenCalledTimes(2); + expect(this.mocks.synthFast).toHaveBeenCalledWith({ + env: expect.objectContaining({ + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + }), + execCmd: ['node', integTestFile], + output: actualSnapshot ?? `cdk-integ.out.${integTestFile}.snapshot`, + }); + + return results; + } +} diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/go.mod b/packages/@aws-cdk/integ-runner/test/language-tests/go.mod new file mode 100644 index 000000000..74af83f27 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/go.mod @@ -0,0 +1,23 @@ +module go-app + +go 1.18 + +require ( + github.com/aws/aws-cdk-go/awscdk/v2 v2.59.0 + github.com/aws/aws-cdk-go/awscdkintegtestsalpha/v2 v2.59.0-alpha.0 + github.com/aws/jsii-runtime-go v1.72.0 +) + +require ( + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/aws/constructs-go/constructs/v10 v10.1.189 // indirect + github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.30 // indirect + github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.1 // indirect + github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv5/v2 v2.0.38 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/yuin/goldmark v1.4.13 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.7.0 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/tools v0.3.0 // indirect +) diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/go.sum b/packages/@aws-cdk/integ-runner/test/language-tests/go.sum new file mode 100644 index 000000000..3e2b98baa --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/go.sum @@ -0,0 +1,45 @@ +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/aws/aws-cdk-go/awscdk/v2 v2.59.0 h1:3s5RSXLarE7wgDYDidQ3IkCYg2XQ+15JahNEHeYEmQM= +github.com/aws/aws-cdk-go/awscdk/v2 v2.59.0/go.mod h1:C6aU5w7MABoOb+uFDW4DoQuL4bwkE56+AW4G6BYHO4k= +github.com/aws/aws-cdk-go/awscdkintegtestsalpha/v2 v2.59.0-alpha.0 h1:QEjZEQn5BbHmMsQLsS/BM4B7HsbvGP2HZofOxcWhc3o= +github.com/aws/aws-cdk-go/awscdkintegtestsalpha/v2 v2.59.0-alpha.0/go.mod h1:g/y63iF97+agyTfBwwMwnAm3KECkeXJPf+ogOjoF8C0= +github.com/aws/constructs-go/constructs/v10 v10.1.189 h1:PmI42w6gXXcXBMZgx6KO0ndHb5xGyUcndV39/nPzxMU= +github.com/aws/constructs-go/constructs/v10 v10.1.189/go.mod h1:Jx57tX1dGJwvmOiqKPIZEUDPY9xKRCd1zag5cg1u5aw= +github.com/aws/jsii-runtime-go v1.72.0 h1:5jMBCUu/qINj0hSt08gkyVyKRbrRBb9RV8ETGxTb+lo= +github.com/aws/jsii-runtime-go v1.72.0/go.mod h1:lExVNqTnEcbS/NMnuovDrHohgmPK3IsGdqvaYLA+N1s= +github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.30 h1:ryT4dP31QvXF7SO3mij6ir+8JBRaHyv1NSd2seUgpH4= +github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.30/go.mod h1:tlNrUd0+vEvsVTA0C1lE0p2txRPrnK53kb44hCuxdDI= +github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.1 h1:l5N27aCCjAB5cgW5pI4/ujnasPL8hUcJ9KBxrKk6UiQ= +github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.1/go.mod h1:CvFHBo0qcg8LUkJqIxQtP1rD/sNGv9bX3L2vHT2FUAo= +github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv5/v2 v2.0.38 h1:IgRq7F3odfHx5cnb+ejlMV+jGTmNOH7pJnSt8ownfvc= +github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv5/v2 v2.0.38/go.mod h1:nh+vhRCLVkw4XOCpller0iKwUxQSs7PbRZnaQ4WoqSw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 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 000000000..6195072f4 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts @@ -0,0 +1,36 @@ +/** + * This test cannot use service modules since it would introduce a circular dependency + * Using CfnResource etc. is a workaround to still test something useful + */ +import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as cdk from 'aws-cdk-lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'TypeScriptStack'); +const queue = new cdk.CfnResource(stack, 'Queue', { + type: 'AWS::SQS::Queue', + properties: { + FifoQueue: true, + }, +}); + +const assertionStack = new cdk.Stack(app, 'TypeScriptAssertions'); +assertionStack.addDependency(stack); + +const integ = new IntegTest(app, 'TypeScript', { + testCases: [stack], + assertionStack, +}); + +integ.assertions + .awsApiCall('SQS', 'getQueueAttributes', { + QueueUrl: stack.exportValue(queue.getAtt('QueueUrl', cdk.ResolutionTypeHint.STRING)), + AttributeNames: ['QueueArn'], + }) + .assertAtPath( + 'Attributes.QueueArn', + ExpectedResult.stringLikeRegexp('.*\\.fifo$'), + ); + +app.synth(); diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptAssertions.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptAssertions.assets.json new file mode 100644 index 000000000..c28870f81 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptAssertions.assets.json @@ -0,0 +1,32 @@ +{ + "version": "22.0.0", + "files": { + "278d42fa865f60954d898636503d0ee86a6689d73dc50eb912fac62def0ef6a4": { + "source": { + "path": "asset.278d42fa865f60954d898636503d0ee86a6689d73dc50eb912fac62def0ef6a4.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "278d42fa865f60954d898636503d0ee86a6689d73dc50eb912fac62def0ef6a4.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "bb131995f97d3bf2ccde6c8fd8d88a6b780ae97a9348985f50b9207d5e341b5c": { + "source": { + "path": "TypeScriptAssertions.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "bb131995f97d3bf2ccde6c8fd8d88a6b780ae97a9348985f50b9207d5e341b5c.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/TypeScriptAssertions.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptAssertions.template.json new file mode 100644 index 000000000..b0014a982 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptAssertions.template.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "AwsApiCallSQSgetQueueAttributes": { + "Type": "Custom::DeployAssert@SdkCallSQSgetQueueAttributes", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "SQS", + "api": "getQueueAttributes", + "expected": "{\"$StringLike\":\".*\\\\.fifo$\"}", + "actualPath": "Attributes.QueueArn", + "parameters": { + "QueueUrl": { + "Fn::ImportValue": "TypeScriptStack:ExportsOutputFnGetAttQueueQueueUrlA8D516BA" + }, + "AttributeNames": [ + "QueueArn" + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "Attributes.QueueArn" + ], + "salt": "1672941547549" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "278d42fa865f60954d898636503d0ee86a6689d73dc50eb912fac62def0ef6a4.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallSQSgetQueueAttributes": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallSQSgetQueueAttributes", + "assertion" + ] + } + } + }, + "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/TypeScriptStack.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptStack.assets.json new file mode 100644 index 000000000..f01cf3ee1 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "a28a0c4ed7dfaee5dec40a71393fffa16401094a480e0340d4713a9bb0677c36": { + "source": { + "path": "TypeScriptStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a28a0c4ed7dfaee5dec40a71393fffa16401094a480e0340d4713a9bb0677c36.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/TypeScriptStack.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptStack.template.json new file mode 100644 index 000000000..c35624996 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/TypeScriptStack.template.json @@ -0,0 +1,57 @@ +{ + "Resources": { + "Queue": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true + } + } + }, + "Outputs": { + "ExportsOutputFnGetAttQueueQueueUrlA8D516BA": { + "Value": { + "Fn::GetAtt": [ + "Queue", + "QueueUrl" + ] + }, + "Export": { + "Name": "TypeScriptStack:ExportsOutputFnGetAttQueueQueueUrlA8D516BA" + } + } + }, + "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 000000000..145739f53 --- /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 000000000..eb715a69a --- /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": { + "TypeScript/DefaultTest": { + "stacks": [ + "TypeScriptStack" + ], + "assertionStack": "TypeScriptAssertions", + "assertionStackName": "TypeScriptAssertions" + } + } +} \ 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 000000000..79dace8e5 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/manifest.json @@ -0,0 +1,142 @@ +{ + "version": "22.0.0", + "artifacts": { + "TypeScriptStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TypeScriptStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TypeScriptStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TypeScriptStack.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}/a28a0c4ed7dfaee5dec40a71393fffa16401094a480e0340d4713a9bb0677c36.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TypeScriptStack.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": [ + "TypeScriptStack.assets" + ], + "metadata": { + "/TypeScriptStack/Queue": [ + { + "type": "aws:cdk:logicalId", + "data": "Queue" + } + ], + "/TypeScriptStack/Exports/Output{\"Fn::GetAtt\":[\"Queue\",\"QueueUrl\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttQueueQueueUrlA8D516BA" + } + ], + "/TypeScriptStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TypeScriptStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TypeScriptStack" + }, + "TypeScriptAssertions.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TypeScriptAssertions.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TypeScriptAssertions": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TypeScriptAssertions.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}/bb131995f97d3bf2ccde6c8fd8d88a6b780ae97a9348985f50b9207d5e341b5c.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TypeScriptAssertions.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": [ + "TypeScriptStack", + "TypeScriptAssertions.assets" + ], + "metadata": { + "/TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallSQSgetQueueAttributes" + } + ], + "/TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallSQSgetQueueAttributes" + } + ], + "/TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/TypeScriptAssertions/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TypeScriptAssertions/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TypeScriptAssertions" + }, + "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 000000000..4006b7c31 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ.typescript-test.ts.snapshot/tree.json @@ -0,0 +1,215 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "TypeScriptStack": { + "id": "TypeScriptStack", + "path": "TypeScriptStack", + "children": { + "Queue": { + "id": "Queue", + "path": "TypeScriptStack/Queue", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "TypeScriptStack/Exports", + "children": { + "Output{\"Fn::GetAtt\":[\"Queue\",\"QueueUrl\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"Queue\",\"QueueUrl\"]}", + "path": "TypeScriptStack/Exports/Output{\"Fn::GetAtt\":[\"Queue\",\"QueueUrl\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TypeScriptStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TypeScriptStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "TypeScriptAssertions": { + "id": "TypeScriptAssertions", + "path": "TypeScriptAssertions", + "children": { + "AwsApiCallSQSgetQueueAttributes": { + "id": "AwsApiCallSQSgetQueueAttributes", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/Default", + "children": { + "Default": { + "id": "Default", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "TypeScriptAssertions/AwsApiCallSQSgetQueueAttributes/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "TypeScriptAssertions/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TypeScriptAssertions/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TypeScriptAssertions/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "TypeScript": { + "id": "TypeScript", + "path": "TypeScript", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "TypeScript/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "TypeScript/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + } + }, + "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.189" + } + } + }, + "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_go-test.go b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go new file mode 100644 index 000000000..3bf5e5313 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go @@ -0,0 +1,43 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" + "github.com/aws/aws-cdk-go/awscdkintegtestsalpha/v2" + "github.com/aws/jsii-runtime-go" +) + +func main() { + defer jsii.Close() + + app := awscdk.NewApp(nil) + stack := awscdk.NewStack(app, jsii.String("GoLangStack"), nil) + + queue := awssqs.NewQueue(stack, jsii.String("Queue"), &awssqs.QueueProps{ + Fifo: jsii.Bool(true), + }) + + integ := awscdkintegtestsalpha.NewIntegTest(app, jsii.String("GoLang"), &awscdkintegtestsalpha.IntegTestProps{ + TestCases: &[]awscdk.Stack{ + stack, + }, + }) + + integ.Assertions().AwsApiCall( + jsii.String("SQS"), + jsii.String("getQueueAttributes"), + struct { + QueueUrl *string + AttributeNames []string + }{ + QueueUrl: queue.QueueUrl(), + AttributeNames: []string{"QueueArn"}, + }, + &[]*string{}, + ).AssertAtPath( + jsii.String("Attributes.QueueArn"), + awscdkintegtestsalpha.ExpectedResult_StringLikeRegexp(jsii.String(".*\\.fifo$")), + ) + + app.Synth(nil) +} diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.assets.json new file mode 100644 index 000000000..45b4d060e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.assets.json @@ -0,0 +1,32 @@ +{ + "version": "22.0.0", + "files": { + "8f0c571812657f9654505faac7869bb410c192d7feba2ed7246fcb86f64e36e0": { + "source": { + "path": "asset.8f0c571812657f9654505faac7869bb410c192d7feba2ed7246fcb86f64e36e0.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "8f0c571812657f9654505faac7869bb410c192d7feba2ed7246fcb86f64e36e0.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "f97830f7d4c4e6fff4f1baaeb87c6b6aa3e08f6c008c99b764e519e4d4cd309a": { + "source": { + "path": "GoLangDefaultTestDeployAssertA629E612.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f97830f7d4c4e6fff4f1baaeb87c6b6aa3e08f6c008c99b764e519e4d4cd309a.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_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.template.json new file mode 100644 index 000000000..16a6514b4 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangDefaultTestDeployAssertA629E612.template.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "AwsApiCallSQSgetQueueAttributes": { + "Type": "Custom::DeployAssert@SdkCallSQSgetQueueAttributes", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "SQS", + "api": "getQueueAttributes", + "expected": "{\"$StringLike\":\".*\\\\.fifo$\"}", + "actualPath": "Attributes.QueueArn", + "parameters": { + "QueueUrl": { + "Fn::ImportValue": "GoLangStack:ExportsOutputRefQueue4A7E3555425E8BD3" + }, + "AttributeNames": [ + "QueueArn" + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "Attributes.QueueArn" + ], + "salt": "1672934999538" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "8f0c571812657f9654505faac7869bb410c192d7feba2ed7246fcb86f64e36e0.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallSQSgetQueueAttributes": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallSQSgetQueueAttributes", + "assertion" + ] + } + } + }, + "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_go-test.go.snapshot/GoLangStack.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangStack.assets.json new file mode 100644 index 000000000..77b506700 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "cdf94bfd1a3da2b2708c1e970f501fd2aec8dffea45b036ee1f42e20f5081015": { + "source": { + "path": "GoLangStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cdf94bfd1a3da2b2708c1e970f501fd2aec8dffea45b036ee1f42e20f5081015.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_go-test.go.snapshot/GoLangStack.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangStack.template.json new file mode 100644 index 000000000..c16a95c27 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/GoLangStack.template.json @@ -0,0 +1,56 @@ +{ + "Resources": { + "Queue4A7E3555": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "ExportsOutputRefQueue4A7E3555425E8BD3": { + "Value": { + "Ref": "Queue4A7E3555" + }, + "Export": { + "Name": "GoLangStack:ExportsOutputRefQueue4A7E3555425E8BD3" + } + } + }, + "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_go-test.go.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/cdk.out new file mode 100644 index 000000000..145739f53 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.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_go-test.go.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/integ.json new file mode 100644 index 000000000..300810713 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "22.0.0", + "testCases": { + "GoLang/DefaultTest": { + "stacks": [ + "GoLangStack" + ], + "assertionStack": "GoLang/DefaultTest/DeployAssert", + "assertionStackName": "GoLangDefaultTestDeployAssertA629E612" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/manifest.json new file mode 100644 index 000000000..04cfcc495 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/manifest.json @@ -0,0 +1,142 @@ +{ + "version": "22.0.0", + "artifacts": { + "GoLangStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "GoLangStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "GoLangStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "GoLangStack.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}/cdf94bfd1a3da2b2708c1e970f501fd2aec8dffea45b036ee1f42e20f5081015.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "GoLangStack.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": [ + "GoLangStack.assets" + ], + "metadata": { + "/GoLangStack/Queue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Queue4A7E3555" + } + ], + "/GoLangStack/Exports/Output{\"Ref\":\"Queue4A7E3555\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefQueue4A7E3555425E8BD3" + } + ], + "/GoLangStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/GoLangStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "GoLangStack" + }, + "GoLangDefaultTestDeployAssertA629E612.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "GoLangDefaultTestDeployAssertA629E612.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "GoLangDefaultTestDeployAssertA629E612": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "GoLangDefaultTestDeployAssertA629E612.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}/f97830f7d4c4e6fff4f1baaeb87c6b6aa3e08f6c008c99b764e519e4d4cd309a.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "GoLangDefaultTestDeployAssertA629E612.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": [ + "GoLangStack", + "GoLangDefaultTestDeployAssertA629E612.assets" + ], + "metadata": { + "/GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallSQSgetQueueAttributes" + } + ], + "/GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallSQSgetQueueAttributes" + } + ], + "/GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/GoLang/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/GoLang/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "GoLang/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_go-test.go.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/tree.json new file mode 100644 index 000000000..c8f29007a --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_go-test.go.snapshot/tree.json @@ -0,0 +1,231 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "GoLangStack": { + "id": "GoLangStack", + "path": "GoLangStack", + "children": { + "Queue": { + "id": "Queue", + "path": "GoLangStack/Queue", + "children": { + "Resource": { + "id": "Resource", + "path": "GoLangStack/Queue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": { + "fifoQueue": true + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "2.59.0" + } + }, + "Exports": { + "id": "Exports", + "path": "GoLangStack/Exports", + "children": { + "Output{\"Ref\":\"Queue4A7E3555\"}": { + "id": "Output{\"Ref\":\"Queue4A7E3555\"}", + "path": "GoLangStack/Exports/Output{\"Ref\":\"Queue4A7E3555\"}", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "GoLangStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.59.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "GoLangStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.59.0" + } + }, + "GoLang": { + "id": "GoLang", + "path": "GoLang", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "GoLang/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "GoLang/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "GoLang/DefaultTest/DeployAssert", + "children": { + "AwsApiCallSQSgetQueueAttributes": { + "id": "AwsApiCallSQSgetQueueAttributes", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.AssertionsProvider", + "version": "2.59.0-alpha.0" + } + }, + "Default": { + "id": "Default", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default", + "children": { + "Default": { + "id": "Default", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "2.59.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "GoLang/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/AssertionResults", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.AwsApiCall", + "version": "2.59.0-alpha.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "2.59.0" + } + }, + "Role": { + "id": "Role", + "path": "GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.59.0" + } + }, + "Handler": { + "id": "Handler", + "path": "GoLang/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "GoLang/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.59.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "GoLang/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.59.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.59.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.59.0-alpha.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.59.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 000000000..4e3365cf7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py @@ -0,0 +1,17 @@ +import aws_cdk as cdk +import aws_cdk.aws_sqs as sqs +from aws_cdk.integ_tests_alpha import IntegTest, ExpectedResult + +app = cdk.App() +stack = cdk.Stack(app, 'PythonStack') + +queue = sqs.Queue(stack, 'Queue', fifo=True) + +integ = IntegTest(app, "Python", test_cases=[stack]) + +integ.assertions.aws_api_call('SQS', 'getQueueAttributes', { + "QueueUrl": queue.queue_url, + "AttributeNames": ["QueueArn"] +}).assert_at_path('Attributes.QueueArn', ExpectedResult.string_like_regexp(".*\\.fifo$")) + +app.synth() diff --git a/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonDefaultTestDeployAssert82E20B88.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonDefaultTestDeployAssert82E20B88.assets.json new file mode 100644 index 000000000..16240eb9f --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonDefaultTestDeployAssert82E20B88.assets.json @@ -0,0 +1,32 @@ +{ + "version": "22.0.0", + "files": { + "c519532b68b7cbc9ca6fcad1d1b608452f0cba5889291ec0aecc40c5b48ec1b3": { + "source": { + "path": "asset.c519532b68b7cbc9ca6fcad1d1b608452f0cba5889291ec0aecc40c5b48ec1b3.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "c519532b68b7cbc9ca6fcad1d1b608452f0cba5889291ec0aecc40c5b48ec1b3.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "4ba4a227fd62b83817c85595e9fcb22091b0c088a429a8eea7bd06560b18e2d2": { + "source": { + "path": "PythonDefaultTestDeployAssert82E20B88.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4ba4a227fd62b83817c85595e9fcb22091b0c088a429a8eea7bd06560b18e2d2.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/PythonDefaultTestDeployAssert82E20B88.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonDefaultTestDeployAssert82E20B88.template.json new file mode 100644 index 000000000..01e247643 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonDefaultTestDeployAssert82E20B88.template.json @@ -0,0 +1,139 @@ +{ + "Resources": { + "AwsApiCallSQSgetQueueAttributes": { + "Type": "Custom::DeployAssert@SdkCallSQSgetQueueAttributes", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "SQS", + "api": "getQueueAttributes", + "expected": "{\"$StringLike\":\".*\\\\.fifo$\"}", + "actualPath": "Attributes.QueueArn", + "parameters": { + "QueueUrl": { + "Fn::ImportValue": "PythonStack:ExportsOutputRefQueue4A7E3555425E8BD3" + }, + "AttributeNames": [ + "QueueArn" + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "Attributes.QueueArn" + ], + "salt": "1672925608158" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "c519532b68b7cbc9ca6fcad1d1b608452f0cba5889291ec0aecc40c5b48ec1b3.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallSQSgetQueueAttributes": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallSQSgetQueueAttributes", + "assertion" + ] + } + } + }, + "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/PythonStack.assets.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonStack.assets.json new file mode 100644 index 000000000..3a7478edb --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "f73d32c184c3aacfc0baa0a075665e95c9a8065be2690b7c556d2bd78b5d796b": { + "source": { + "path": "PythonStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f73d32c184c3aacfc0baa0a075665e95c9a8065be2690b7c556d2bd78b5d796b.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/PythonStack.template.json b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonStack.template.json new file mode 100644 index 000000000..2fbdbd5bd --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/PythonStack.template.json @@ -0,0 +1,56 @@ +{ + "Resources": { + "Queue4A7E3555": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "ExportsOutputRefQueue4A7E3555425E8BD3": { + "Value": { + "Ref": "Queue4A7E3555" + }, + "Export": { + "Name": "PythonStack:ExportsOutputRefQueue4A7E3555425E8BD3" + } + } + }, + "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 000000000..145739f53 --- /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 000000000..a58a27dd5 --- /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": { + "Python/DefaultTest": { + "stacks": [ + "PythonStack" + ], + "assertionStack": "Python/DefaultTest/DeployAssert", + "assertionStackName": "PythonDefaultTestDeployAssert82E20B88" + } + } +} \ 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 000000000..8d2793db7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/manifest.json @@ -0,0 +1,142 @@ +{ + "version": "22.0.0", + "artifacts": { + "PythonStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PythonStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PythonStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PythonStack.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}/f73d32c184c3aacfc0baa0a075665e95c9a8065be2690b7c556d2bd78b5d796b.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PythonStack.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": [ + "PythonStack.assets" + ], + "metadata": { + "/PythonStack/Queue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Queue4A7E3555" + } + ], + "/PythonStack/Exports/Output{\"Ref\":\"Queue4A7E3555\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefQueue4A7E3555425E8BD3" + } + ], + "/PythonStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PythonStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PythonStack" + }, + "PythonDefaultTestDeployAssert82E20B88.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PythonDefaultTestDeployAssert82E20B88.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PythonDefaultTestDeployAssert82E20B88": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PythonDefaultTestDeployAssert82E20B88.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}/4ba4a227fd62b83817c85595e9fcb22091b0c088a429a8eea7bd06560b18e2d2.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PythonDefaultTestDeployAssert82E20B88.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": [ + "PythonStack", + "PythonDefaultTestDeployAssert82E20B88.assets" + ], + "metadata": { + "/Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallSQSgetQueueAttributes" + } + ], + "/Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallSQSgetQueueAttributes" + } + ], + "/Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/Python/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Python/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Python/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 000000000..fded17177 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/language-tests/integ_python-test.py.snapshot/tree.json @@ -0,0 +1,231 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "PythonStack": { + "id": "PythonStack", + "path": "PythonStack", + "children": { + "Queue": { + "id": "Queue", + "path": "PythonStack/Queue", + "children": { + "Resource": { + "id": "Resource", + "path": "PythonStack/Queue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": { + "fifoQueue": true + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "2.55.0" + } + }, + "Exports": { + "id": "Exports", + "path": "PythonStack/Exports", + "children": { + "Output{\"Ref\":\"Queue4A7E3555\"}": { + "id": "Output{\"Ref\":\"Queue4A7E3555\"}", + "path": "PythonStack/Exports/Output{\"Ref\":\"Queue4A7E3555\"}", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PythonStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.55.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PythonStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.55.0" + } + }, + "Python": { + "id": "Python", + "path": "Python", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Python/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Python/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Python/DefaultTest/DeployAssert", + "children": { + "AwsApiCallSQSgetQueueAttributes": { + "id": "AwsApiCallSQSgetQueueAttributes", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.AssertionsProvider", + "version": "2.55.0-alpha.0" + } + }, + "Default": { + "id": "Default", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default", + "children": { + "Default": { + "id": "Default", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/Default/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "2.55.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "Python/DefaultTest/DeployAssert/AwsApiCallSQSgetQueueAttributes/AssertionResults", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.AwsApiCall", + "version": "2.55.0-alpha.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "2.55.0" + } + }, + "Role": { + "id": "Role", + "path": "Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.55.0" + } + }, + "Handler": { + "id": "Handler", + "path": "Python/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.55.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.190" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Python/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.55.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Python/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 new file mode 100644 index 000000000..82cbef77b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/integ-test-runner.test.ts @@ -0,0 +1,702 @@ +import * as child_process from 'child_process'; +import * as builtinFs from 'fs'; +import { HotswapMode } from '@aws-cdk/cdk-cli-wrapper'; +import { Manifest } from '@aws-cdk/cloud-assembly-schema'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY } from '@aws-cdk/cx-api'; +import * as fs from 'fs-extra'; +import { IntegTestRunner, IntegTest } from '../../lib/runner'; +import { MockCdkProvider } from '../helpers'; + +let cdkMock: MockCdkProvider; +let spawnSyncMock: jest.SpyInstance; +let removeSyncMock: jest.SpyInstance; +beforeEach(() => { + cdkMock = new MockCdkProvider({ directory: 'test/test-data' }); + cdkMock.mockAll().list.mockImplementation(() => 'stackabc'); + jest.spyOn(Manifest, 'saveIntegManifest').mockImplementation(); + + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { + return true; + }); + removeSyncMock = jest.spyOn(fs, 'removeSync').mockImplementation(() => { + return true; + }); + + // fs-extra delegates to the built-in one, this also catches calls done directly + jest.spyOn(builtinFs, 'writeFileSync').mockImplementation(() => { + return true; + }); +}); + +afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); +}); + +describe('IntegTest runIntegTests', () => { + test('with defaults', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(3); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith({ + app: 'xxxxx.test-with-snapshot.js.snapshot', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + profile: undefined, + versionReporting: false, + lookups: false, + stacks: ['test-stack'], + }); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith({ + app: 'node xxxxx.test-with-snapshot.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + output: 'cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot', + profile: undefined, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + versionReporting: false, + lookups: false, + stacks: ['test-stack', 'new-test-stack'], + }); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith({ + app: 'node xxxxx.test-with-snapshot.js', + pathMetadata: false, + assetMetadata: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + versionReporting: false, + profile: undefined, + force: true, + all: true, + output: 'cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot', + }); + }); + + test('no snapshot', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.integ-test1', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith({ + app: 'node xxxxx.integ-test1.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + profile: undefined, + context: expect.not.objectContaining({ + [AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY]: ['test-region-1a', 'test-region-1b', 'test-region-1c'], + }), + lookups: false, + stacks: ['stack1'], + output: 'cdk-integ.out.xxxxx.integ-test1.js.snapshot', + }); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith({ + app: 'node xxxxx.integ-test1.js', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + context: expect.any(Object), + force: true, + all: true, + output: 'cdk-integ.out.xxxxx.integ-test1.js.snapshot', + }); + }); + + test('with lookups', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot-assets-diff.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot-assets-diff', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(2); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith({ + app: 'node xxxxx.test-with-snapshot-assets-diff.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + versionReporting: false, + lookups: true, + stacks: ['test-stack'], + output: 'cdk-integ.out.xxxxx.test-with-snapshot-assets-diff.js.snapshot', + profile: undefined, + }); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledWith({ + execCmd: ['node', 'xxxxx.test-with-snapshot-assets-diff.js'], + env: expect.objectContaining({ + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + CDK_CONTEXT_JSON: expect.stringContaining('"vpcId":"vpc-60900905"'), + }), + output: 'xxxxx.test-with-snapshot-assets-diff.js.snapshot', + }); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith({ + app: 'node xxxxx.test-with-snapshot-assets-diff.js', + pathMetadata: false, + assetMetadata: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + versionReporting: false, + force: true, + all: true, + output: 'cdk-integ.out.xxxxx.test-with-snapshot-assets-diff.js.snapshot', + }); + }); + + test('with an assertion stack', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(3); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.deploy).toHaveBeenNthCalledWith(1, expect.objectContaining({ + app: 'xxxxx.test-with-snapshot.js.snapshot', + context: expect.any(Object), + stacks: ['test-stack'], + })); + expect(cdkMock.mocks.deploy).toHaveBeenNthCalledWith(2, expect.not.objectContaining({ + rollback: false, + })); + expect(cdkMock.mocks.deploy).toHaveBeenNthCalledWith(3, expect.objectContaining({ + app: 'node xxxxx.test-with-snapshot.js', + stacks: ['Bundling/DefaultTest/DeployAssert'], + rollback: false, + })); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith({ + app: 'node xxxxx.test-with-snapshot.js', + pathMetadata: false, + assetMetadata: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + versionReporting: false, + force: true, + all: true, + output: 'cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot', + }); + }); + + test('no clean', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.integ-test1', + clean: false, + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(0); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + }); + + test('dryrun', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.integ-test1', + dryRun: true, + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(0); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(0); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(2); + }); + + test('generate snapshot', () => { + // WHEN + new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }), + }); + + // THEN + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledWith({ + execCmd: ['node', 'xxxxx.integ-test1.js'], + output: 'cdk-integ.out.xxxxx.integ-test1.js.snapshot', + env: expect.objectContaining({ + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + }), + }); + }); + + test('with profile', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }), + profile: 'test-profile', + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.integ-test1', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith({ + app: 'node xxxxx.integ-test1.js', + requireApproval: 'never', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + profile: 'test-profile', + lookups: false, + stacks: ['stack1'], + output: 'cdk-integ.out.xxxxx.integ-test1.js.snapshot', + }); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith({ + app: 'node xxxxx.integ-test1.js', + pathMetadata: false, + assetMetadata: false, + versionReporting: false, + context: expect.not.objectContaining({ + 'vpc-provider:account=12345678:filter.isDefault=true:region=test-region:returnAsymmetricSubnets=true': expect.objectContaining({ + vpcId: 'vpc-60900905', + }), + }), + profile: 'test-profile', + force: true, + all: true, + output: 'cdk-integ.out.xxxxx.integ-test1.js.snapshot', + }); + }); + + test('with hooks', () => { + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot-assets.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot-assets', + }); + + // THEN + expect(spawnSyncMock.mock.calls).toEqual(expect.arrayContaining([ + expect.arrayContaining([ + 'echo', ['"preDeploy hook"'], + ]), + expect.arrayContaining([ + 'echo', ['"postDeploy hook"'], + ]), + expect.arrayContaining([ + 'echo', ['"preDestroy hook"'], + ]), + expect.arrayContaining([ + 'echo', ['"postDestroy hook"'], + ]), + expect.arrayContaining([ + 'ls', [], + ]), + expect.arrayContaining([ + 'echo', ['-n', '"No new line"'], + ]), + ])); + }); + + test('git is used to checkout latest snapshot', () => { + // GIVEN + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('HEAD branch: main'), + stdout: Buffer.from('HEAD branch: main'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }).mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('abc'), + stdout: Buffer.from('abc'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(spawnSyncMock.mock.calls).toEqual(expect.arrayContaining([ + expect.arrayContaining([ + 'git', ['remote', 'show', 'origin'], + ]), + expect.arrayContaining([ + 'git', ['merge-base', 'HEAD', 'main'], + ]), + expect.arrayContaining([ + 'git', ['checkout', 'abc', '--', 'xxxxx.test-with-snapshot.js.snapshot'], + ]), + ])); + }); + + test('git is used and cannot determine origin', () => { + // GIVEN + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValueOnce({ + status: 1, + stderr: Buffer.from('HEAD branch: main'), + stdout: Buffer.from('HEAD branch: main'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ + expect.arrayContaining([ + expect.stringMatching(/Could not determine git origin branch/), + ]), + ])); + }); + + test('git is used and cannot checkout snapshot', () => { + // GIVEN + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('HEAD branch: main'), + stdout: Buffer.from('HEAD branch: main'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }).mockReturnValueOnce({ + status: 1, + stderr: Buffer.from('HEAD branch: main'), + stdout: Buffer.from('HEAD branch: main'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ + expect.arrayContaining([ + expect.stringMatching(/Could not checkout snapshot directory/), + ]), + ])); + }); + + test('with assets manifest, assets are removed if stackUpdateWorkflow is disabled', () => { + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot-assets.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot-assets', + }); + + expect(removeSyncMock.mock.calls).toEqual([ + ['test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot'], + ['test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot'], + [ + 'test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824', + ], + ['test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot'], + ]); + }); + + test('with assembly manifest, assets are removed if stackUpdateWorkflow is disabled', () => { + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot-assets-diff.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot-assets-diff', + }); + + expect(removeSyncMock.mock.calls).toEqual([ + ['test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot'], + [ + 'test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/asset.fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509', + ], + ]); + }); + + test.each` + verbosity | verbose | debug + ${0} | ${undefined} | ${undefined} + ${1} | ${undefined} | ${undefined} + ${2} | ${undefined} | ${undefined} + ${3} | ${true} | ${undefined} + ${4} | ${true} | ${true} +`('with verbosity set to $verbosity', ({ verbosity, verbose, debug }) => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + verbosity: verbosity, + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith(expect.objectContaining({ + verbose, + debug, + })); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith(expect.objectContaining({ + verbose, + debug, + })); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith(expect.objectContaining({ + verbose, + debug, + })); + }); + + test('with custom app run command', () => { + // WHEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + appCommand: 'node --no-warnings {filePath}', + }), + }); + integTest.runIntegTestCase({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(cdkMock.mocks.deploy).toHaveBeenCalledTimes(3); + expect(cdkMock.mocks.destroy).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.deploy).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + })); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledWith(expect.objectContaining({ + execCmd: ['node', '--no-warnings', 'xxxxx.test-with-snapshot.js'], + })); + expect(cdkMock.mocks.destroy).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + })); + }); +}); + +describe('IntegTest watchIntegTest', () => { + test('default watch', async () => { + // GIVEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + appCommand: 'node --no-warnings {filePath}', + }), + }); + + // WHEN + await integTest.watchIntegTest({ + testCaseName: 'xxxxx.test-with-snapshot', + }); + + // THEN + expect(cdkMock.mocks.watch).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + hotswap: HotswapMode.FALL_BACK, + watch: true, + traceLogs: false, + deploymentMethod: 'direct', + verbose: undefined, + })); + }); + + test('verbose watch', async () => { + // GIVEN + const integTest = new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + appCommand: 'node --no-warnings {filePath}', + }), + }); + + // WHEN + await integTest.watchIntegTest({ + testCaseName: 'xxxxx.test-with-snapshot', + verbosity: 2, + }); + + // THEN + expect(cdkMock.mocks.watch).toHaveBeenCalledWith(expect.objectContaining({ + app: 'node --no-warnings xxxxx.test-with-snapshot.js', + hotswap: HotswapMode.FALL_BACK, + watch: true, + traceLogs: true, + deploymentMethod: 'direct', + verbose: undefined, + })); + }); + + test('with error', () => { + expect(() => { + // WHEN + new IntegTestRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.test-with-error.js', + discoveryRoot: 'test/test-data', + }), + }); + // THEN + }).toThrow('xxxxx.test-with-error is a new test. Please use the IntegTest construct to configure the test\nhttps://github.com/aws/aws-cdk/tree/main/packages/%40aws-cdk/integ-tests-alpha'); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/integ-test-suite.test.ts b/packages/@aws-cdk/integ-runner/test/runner/integ-test-suite.test.ts new file mode 100644 index 000000000..929b35405 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/integ-test-suite.test.ts @@ -0,0 +1,287 @@ +import * as path from 'path'; +import * as mockfs from 'mock-fs'; +import { IntegTestSuite, LegacyIntegTestSuite } from '../../lib/runner/integ-test-suite'; +import type { MockCdkMocks } from '../helpers'; +import { MockCdkProvider } from '../helpers'; + +describe('Integration test cases', () => { + const testsFile = '/tmp/foo/bar/does/not/exist/integ.json'; + afterEach(() => { + mockfs.restore(); + }); + + test('basic manifest', () => { + // GIVEN + mockfs({ + [testsFile]: JSON.stringify({ + version: 'v1.0.0', + testCases: { + test1: { + stacks: [ + 'test-stack', + ], + }, + }, + }), + }); + // WHEN + const testCases = IntegTestSuite.fromPath(path.dirname(testsFile)); + + // THEN + expect(testCases.enableLookups).toEqual(false); + expect(testCases.getStacksWithoutUpdateWorkflow().length).toEqual(0); + expect(testCases.testSuite).toEqual({ + test1: { + stacks: [ + 'test-stack', + ], + }, + }); + }); + + test('manifest with non defaults', () => { + // GIVEN + mockfs({ + [testsFile]: JSON.stringify({ + version: 'v1.0.0', + enableLookups: true, + testCases: { + test1: { + stackUpdateWorkflow: false, + diffAssets: true, + allowDestroy: ['AWS::IAM::Role'], + stacks: [ + 'test-stack', + ], + }, + }, + }), + }); + // WHEN + const testCases = IntegTestSuite.fromPath(path.dirname(testsFile)); + + // THEN + expect(testCases.enableLookups).toEqual(true); + expect(testCases.getStacksWithoutUpdateWorkflow().length).toEqual(1); + expect(testCases.testSuite).toEqual({ + test1: { + stackUpdateWorkflow: false, + diffAssets: true, + allowDestroy: ['AWS::IAM::Role'], + stacks: [ + 'test-stack', + ], + }, + }); + }); + + test('get options for stack', () => { + // GIVEN + mockfs({ + [testsFile]: JSON.stringify({ + version: 'v1.0.0', + enableLookups: true, + testCases: { + test1: { + stackUpdateWorkflow: false, + diffAssets: true, + allowDestroy: ['AWS::IAM::Role'], + stacks: [ + 'test-stack1', + ], + }, + test2: { + diffAssets: false, + stacks: [ + 'test-stack2', + ], + }, + }, + }), + }); + // WHEN + const testCases = IntegTestSuite.fromPath(path.dirname(testsFile)); + + // THEN + expect(testCases.getOptionsForStack('test-stack1')).toEqual({ + diffAssets: true, + regions: undefined, + hooks: undefined, + cdkCommandOptions: undefined, + stackUpdateWorkflow: false, + allowDestroy: ['AWS::IAM::Role'], + }); + expect(testCases.getOptionsForStack('test-stack2')).toEqual({ + diffAssets: false, + allowDestroy: undefined, + regions: undefined, + hooks: undefined, + stackUpdateWorkflow: true, + cdkCommandOptions: undefined, + }); + expect(testCases.getOptionsForStack('test-stack-does-not-exist')).toBeUndefined(); + }); +}); + +describe('Legacy Integration test cases', () => { + let cdkMock: MockCdkProvider; + let listMock: MockCdkMocks['list']; + const testsFile = '/tmp/foo/bar/does/not/exist/integ.test.js'; + beforeEach(() => { + cdkMock = new MockCdkProvider({ directory: 'test/test-data' }); + }); + + afterEach(() => { + mockfs.restore(); + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + }); + + test('basic manifest', () => { + // GIVEN + mockfs({ + [testsFile]: '/// !cdk-integ test-stack', + }); + listMock = jest.fn().mockImplementation(() => { + return 'stackabc'; + }); + cdkMock.mockList(listMock); + + // WHEN + const testCases = LegacyIntegTestSuite.fromLegacy({ + cdk: cdkMock.cdk, + testName: 'test', + listOptions: {}, + integSourceFilePath: testsFile, + }); + + // THEN + expect(listMock).not.toHaveBeenCalled(); + expect(testCases.enableLookups).toEqual(false); + expect(testCases.getStacksWithoutUpdateWorkflow().length).toEqual(0); + expect(testCases.testSuite).toEqual({ + test: { + stackUpdateWorkflow: true, + diffAssets: false, + stacks: [ + 'test-stack', + ], + }, + }); + }); + + test('manifest with pragma', () => { + // GIVEN + mockfs({ + [testsFile]: '/// !cdk-integ test-stack pragma:enable-lookups pragma:disable-update-workflow pragma:include-assets-hashes', + }); + listMock = jest.fn().mockImplementation(() => { + return 'stackabc'; + }); + cdkMock.mockList(listMock); + + // WHEN + const testCases = LegacyIntegTestSuite.fromLegacy({ + cdk: cdkMock.cdk, + testName: 'test', + listOptions: {}, + integSourceFilePath: testsFile, + }); + + // THEN + expect(listMock).not.toHaveBeenCalled(); + expect(testCases.enableLookups).toEqual(true); + expect(testCases.getStacksWithoutUpdateWorkflow().length).toEqual(1); + expect(testCases.testSuite).toEqual({ + test: { + stackUpdateWorkflow: false, + diffAssets: true, + stacks: [ + 'test-stack', + ], + }, + }); + }); + + test('manifest with no pragma', () => { + // GIVEN + mockfs({ + [testsFile]: '', + }); + listMock = jest.fn().mockImplementation(() => { + return 'stackabc'; + }); + cdkMock.mockList(listMock); + + // WHEN + const testCases = LegacyIntegTestSuite.fromLegacy({ + cdk: cdkMock.cdk, + testName: 'test', + listOptions: {}, + integSourceFilePath: testsFile, + }); + + // THEN + expect(listMock).toHaveBeenCalled(); + expect(testCases.enableLookups).toEqual(false); + expect(testCases.getStacksWithoutUpdateWorkflow().length).toEqual(0); + expect(testCases.testSuite).toEqual({ + test: { + stackUpdateWorkflow: true, + diffAssets: false, + stacks: [ + 'stackabc', + ], + }, + }); + }); + + test('manifest with no pragma and multiple stack throws', () => { + // GIVEN + mockfs({ + [testsFile]: '', + }); + listMock = jest.fn().mockImplementation(() => { + return 'stack1\nstack2'; + }); + cdkMock.mockList(listMock); + + // THEN + expect(() => { + LegacyIntegTestSuite.fromLegacy({ + cdk: cdkMock.cdk, + testName: 'test', + listOptions: {}, + integSourceFilePath: testsFile, + }); + }).toThrow(); + }); + + test('can get context from pragma', () => { + // GIVEN + mockfs({ + [testsFile]: '/// !cdk-integ test-stack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true', + }); + + // WHEN + const context = LegacyIntegTestSuite.getPragmaContext(testsFile); + + // THEN + expect(context).toEqual({ + '@aws-cdk/core:newStyleStackSynthesis': 'true', + }); + }); + + test('invalid pragma context throws', () => { + // GIVEN + mockfs({ + [testsFile]: '/// !cdk-integ test-stack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis true', + }); + + // WHEN + expect(() => { + LegacyIntegTestSuite.getPragmaContext(testsFile); + }).toThrow(); + }); +}); 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 new file mode 100644 index 000000000..a204743c6 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/integration-tests.test.ts @@ -0,0 +1,133 @@ +import * as mockfs from 'mock-fs'; +import { IntegrationTests } from '../../lib/runner/integration-tests'; + +describe('IntegrationTests Discovery', () => { + const tests = new IntegrationTests('test'); + let stderrMock: jest.SpyInstance; + stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + + beforeEach(() => { + mockfs({ + 'test/test-data': { + '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': 'javascript', + 'integ.other-test1.ts': 'typescript', + 'integ_other-test1.py': 'python', + }, + }); + }); + + afterEach(() => { + mockfs.restore(); + stderrMock.mockReset(); + }); + + describe.each([ + ['javascript', 'js', 'integ.test1.js'], + ['typescript', 'ts', 'integ.test1.ts'], + ['python', 'py', 'integ_test1.py'], + ])('%s', (language, fileExtension, namedTest) => { + const cliOptions = { + language: [language], + }; + + test('assert test inputs', () => { + expect(namedTest).toContain('.' + fileExtension); + }); + + describe('from cli args', () => { + test('find all', async () => { + const integTests = await tests.fromCliOptions(cliOptions); + + 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.fromCliOptions({ ...cliOptions, 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.fromCliOptions({ ...cliOptions, 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.fromCliOptions({ ...cliOptions, 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.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.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}$`))); + }); + }); + }); + + describe('Same test file in JS and TS is only running JS', () => { + const cliOptions = { + language: ['javascript', 'typescript'], + }; + + test('find only JS files', async () => { + const integTests = await tests.fromCliOptions(cliOptions); + + expect(integTests.length).toEqual(3); + expect(integTests[0].fileName).toEqual(expect.stringMatching(new RegExp('^.*test1\\.js$'))); + expect(integTests[1].fileName).toEqual(expect.stringMatching(new RegExp('^.*test2\\.js$'))); + expect(integTests[2].fileName).toEqual(expect.stringMatching(new RegExp('^.*test3\\.js$'))); + }); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/private/cloud-assembly.test.ts b/packages/@aws-cdk/integ-runner/test/runner/private/cloud-assembly.test.ts new file mode 100644 index 000000000..721e4cd52 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/private/cloud-assembly.test.ts @@ -0,0 +1,297 @@ +import * as path from 'path'; +import { Manifest } from '@aws-cdk/cloud-assembly-schema'; +import * as mockfs from 'mock-fs'; +import { AssemblyManifestReader } from '../../../lib/runner/private/cloud-assembly'; + +describe('cloud assembly manifest reader', () => { + const manifestFile = '/tmp/foo/bar/does/not/exist/manifest.json'; + const manifestStack = '/tmp/foo/bar/does/not/exist/test-stack.template.json'; + beforeEach(() => { + mockfs({ + [manifestStack]: JSON.stringify({ + data: 'data', + }), + [manifestFile]: JSON.stringify({ + version: '17.0.0', + artifacts: { + 'Tree': { + type: 'cdk:tree', + properties: { + file: 'tree.json', + }, + }, + 'test-stack': { + type: 'aws:cloudformation:stack', + environment: 'aws://unknown-account/unknown-region', + properties: { + templateFile: 'test-stack.template.json', + validateOnSynth: false, + }, + metadata: { + '/test-stack/MyFunction1/ServiceRole/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction1ServiceRole9852B06B', + trace: [ + 'some trace', + 'some more trace', + ], + }, + ], + '/test-stack/MyFunction1/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction12A744C2E', + trace: [ + 'some trace', + 'some more trace', + ], + }, + ], + }, + displayName: 'test-stack', + }, + 'test-stack2': { + type: 'aws:cloudformation:stack', + environment: 'aws://unknown-account/unknown-region', + properties: { + templateFile: 'test-stack.template.json', + validateOnSynth: false, + }, + metadata: { + '/test-stack/asset1': [ + { + type: 'aws:cdk:asset', + data: { + path: 'asset.a820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91', + }, + }, + ], + '/test-stack/asset2': [ + { + type: 'aws:cdk:asset', + data: { + path: 'test-stack2.template.json', + }, + }, + ], + '/test-stack/MyFunction1/ServiceRole/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction1ServiceRole9852B06B', + trace: [ + 'some trace', + 'some more trace', + ], + }, + ], + '/test-stack/MyFunction1/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction12A744C2E', + trace: [ + 'some trace', + 'some more trace', + ], + }, + ], + }, + displayName: 'test-stack', + }, + }, + }), + }); + }); + + afterEach(() => { + mockfs.restore(); + }); + + test('can read manifest from file', () => { + expect(() => { + AssemblyManifestReader.fromFile(manifestFile); + }).not.toThrow(); + }); + + test('throws if manifest not found', () => { + expect(() => { + AssemblyManifestReader.fromFile('some-other-file'); + }).toThrow(/Cannot read integ manifest 'some-other-file':/); + }); + + test('can read manifest from path', () => { + expect(() => { + AssemblyManifestReader.fromPath(path.dirname(manifestFile)); + }).not.toThrow(); + }); + + test('fromPath sets directory correctly', () => { + const manifest = AssemblyManifestReader.fromPath(path.dirname(manifestFile)); + expect(manifest.directory).toEqual('/tmp/foo/bar/does/not/exist'); + }); + + test('can get stacks from manifest', () => { + const manifest = AssemblyManifestReader.fromFile(manifestFile); + + expect(manifest.stacks).toEqual({ + 'test-stack': { data: 'data' }, + 'test-stack2': { data: 'data' }, + }); + }); + + test('can clean stack trace', () => { + // WHEN + const manifest = AssemblyManifestReader.fromFile(manifestFile); + manifest.cleanManifest(); + + // THEN + const newManifest = Manifest.loadAssetManifest(manifestFile); + expect(newManifest).toEqual({ + version: expect.any(String), + artifacts: expect.objectContaining({ + 'Tree': { + type: 'cdk:tree', + properties: { + file: 'tree.json', + }, + }, + 'test-stack': { + type: 'aws:cloudformation:stack', + environment: 'aws://unknown-account/unknown-region', + properties: { + templateFile: 'test-stack.template.json', + validateOnSynth: false, + }, + metadata: { + '/test-stack/MyFunction1/ServiceRole/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction1ServiceRole9852B06B', + }, + ], + '/test-stack/MyFunction1/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction12A744C2E', + }, + ], + }, + displayName: 'test-stack', + }, + }), + }); + }); + + test('can add stack trace', () => { + // WHEN + const manifest = AssemblyManifestReader.fromFile(manifestFile); + manifest.recordTrace(new Map([ + ['test-stack', new Map([ + ['MyFunction12A744C2E', 'some trace'], + ])], + ])); + + // THEN + const newManifest = Manifest.loadAssetManifest(manifestFile); + expect(newManifest).toEqual({ + version: expect.any(String), + artifacts: expect.objectContaining({ + 'Tree': { + type: 'cdk:tree', + properties: { + file: 'tree.json', + }, + }, + 'test-stack': { + type: 'aws:cloudformation:stack', + environment: 'aws://unknown-account/unknown-region', + properties: { + templateFile: 'test-stack.template.json', + validateOnSynth: false, + }, + metadata: { + '/test-stack/MyFunction1/ServiceRole/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction1ServiceRole9852B06B', + }, + ], + '/test-stack/MyFunction1/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction12A744C2E', + trace: ['some trace'], + }, + ], + }, + displayName: 'test-stack', + }, + }), + }); + }); + + test('can add stack trace for old resource', () => { + // WHEN + const manifest = AssemblyManifestReader.fromFile(manifestFile); + manifest.recordTrace(new Map([ + ['test-stack', new Map([ + ['MyFunction', 'some trace'], + ])], + ])); + + // THEN + const newManifest = Manifest.loadAssetManifest(manifestFile); + expect(newManifest).toEqual({ + version: expect.any(String), + artifacts: expect.objectContaining({ + 'Tree': { + type: 'cdk:tree', + properties: { + file: 'tree.json', + }, + }, + 'test-stack': { + type: 'aws:cloudformation:stack', + environment: 'aws://unknown-account/unknown-region', + properties: { + templateFile: 'test-stack.template.json', + validateOnSynth: false, + }, + metadata: { + '/test-stack/MyFunction1/ServiceRole/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction1ServiceRole9852B06B', + }, + ], + '/test-stack/MyFunction1/Resource': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction12A744C2E', + }, + ], + 'MyFunction': [ + { + type: 'aws:cdk:logicalId', + data: 'MyFunction', + trace: ['some trace'], + }, + ], + }, + displayName: 'test-stack', + }, + }), + }); + }); + + test('can get assets from assembly manifest', () => { + // WHEN + const manifest = AssemblyManifestReader.fromFile(manifestFile); + const assets = manifest.getAssetLocationsForStack('test-stack2'); + + // THEN + expect(assets).toEqual([ + 'asset.a820140ad8525b8ed56ad2a7bcd9da99d6afc2490e8c91e34620886c011bdc91', + ]); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/private/integ-manifest.test.ts b/packages/@aws-cdk/integ-runner/test/runner/private/integ-manifest.test.ts new file mode 100644 index 000000000..8dffa0bb6 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/private/integ-manifest.test.ts @@ -0,0 +1,69 @@ +import * as path from 'path'; +import * as mockfs from 'mock-fs'; +import { IntegManifestReader } from '../../../lib/runner/private/integ-manifest'; + +describe('Integ manifest reader', () => { + const manifestFile = '/tmp/foo/bar/does/not/exist/integ.json'; + beforeEach(() => { + mockfs({ + [manifestFile]: JSON.stringify({ + version: 'v1.0.0', + testCases: { + test1: { + stacks: ['MyStack'], + diffAssets: false, + }, + test2: { + stacks: ['MyOtherStack'], + diffAssets: true, + }, + }, + }), + }); + }); + + afterEach(() => { + mockfs.restore(); + }); + + test('can read manifest from file', () => { + expect(() => { + IntegManifestReader.fromFile(manifestFile); + }).not.toThrow(); + }); + + test('throws if manifest not found', () => { + expect(() => { + IntegManifestReader.fromFile('some-other-file'); + }).toThrow(/Cannot read integ manifest 'some-other-file':/); + }); + + test('can read manifest from path', () => { + expect(() => { + IntegManifestReader.fromPath(path.dirname(manifestFile)); + }).not.toThrow(); + }); + + test('fromPath sets directory correctly', () => { + const manifest = IntegManifestReader.fromPath(path.dirname(manifestFile)); + expect(manifest.directory).toEqual('/tmp/foo/bar/does/not/exist'); + }); + + test('can get stacks from manifest', () => { + const manifest = IntegManifestReader.fromFile(manifestFile); + + expect(manifest.tests).toEqual({ + testCases: { + test1: { + stacks: ['MyStack'], + diffAssets: false, + }, + test2: { + stacks: ['MyOtherStack'], + diffAssets: true, + }, + }, + enableLookups: false, + }); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/runner/snapshot-test-runner.test.ts b/packages/@aws-cdk/integ-runner/test/runner/snapshot-test-runner.test.ts new file mode 100644 index 000000000..5303a8379 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/runner/snapshot-test-runner.test.ts @@ -0,0 +1,231 @@ +import * as child_process from 'child_process'; +import * as builtinFs from 'fs'; +import * as path from 'path'; +import * as fs from 'fs-extra'; +import { IntegSnapshotRunner, IntegTest } from '../../lib/runner'; +import { DiagnosticReason } from '../../lib/workers/common'; +import { MockCdkProvider } from '../helpers'; + +let cdkMock: MockCdkProvider; + +const currentCwd = process.cwd(); +beforeAll(() => { + process.chdir(path.join(__dirname, '..', '..')); +}); +afterAll(() => { + process.chdir(currentCwd); +}); + +beforeEach(() => { + cdkMock = new MockCdkProvider({ directory: 'test/test-data' }); + cdkMock.mockAll().list.mockImplementation(() => 'stackabc'); + + jest.spyOn(child_process, 'spawnSync').mockImplementation(); + jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { + return true; + }); + + // fs-extra delegates to the built-in one, this also catches calls done directly + jest.spyOn(builtinFs, 'writeFileSync').mockImplementation(() => { + return true; + }); + jest.spyOn(builtinFs, 'rmdirSync').mockImplementation(() => { + return true; + }); +}); + +afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); +}); + +describe('IntegTest runSnapshotTests', () => { + test('with defaults no diff', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-snapshot.js', 'xxxxx.test-with-snapshot.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual([]); + }); + + test('new stack in actual', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-snapshot.js'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-snapshot', + message: 'new-test-stack does not exist in snapshot, but does in actual', + })])); + }); + + test('with defaults and diff', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-snapshot.js', 'xxxxx.test-with-snapshot-diff.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([ + expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-snapshot', + message: expect.stringContaining('foobar'), + config: { diffAssets: true }, + }), + ])); + expect(results.destructiveChanges).not.toEqual([{ + impact: 'WILL_DESTROY', + logicalId: 'MyFunction1ServiceRole9852B06B', + stackName: 'test-stack', + }]); + expect(results.destructiveChanges).toEqual([{ + impact: 'WILL_DESTROY', + logicalId: 'MyLambdaFuncServiceRoleDefaultPolicyBEB0E748', + stackName: 'test-stack', + }]); + }); + + test('dont diff new asset hashes', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-new-assets-diff.js', 'cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual([]); + }); + + test('diff new asset hashes', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-new-assets.js', 'cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-new-assets', + message: expect.stringContaining('S3Key'), + config: { diffAssets: true }, + }), + expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-new-assets', + message: expect.stringContaining('TemplateURL'), + config: { diffAssets: true }, + })])); + }); + + describe('Nested Stacks', () => { + test('it will compare snapshots for nested stacks', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-nested-stack.js', 'xxxxx.test-with-nested-stack-changed.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-nested-stack', + stackName: expect.stringContaining('teststacknested'), + message: expect.stringContaining('AWS::SNS::Topic'), + config: { diffAssets: false }, + })])); + }); + + test('it will diff assets for nested stacks', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-nested-stack.js', 'xxxxx.test-with-asset-in-nested-stack.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-nested-stack', + stackName: expect.stringContaining('teststacknested'), + message: expect.stringContaining('S3Key'), + config: { diffAssets: true }, + })])); + }); + }); + + describe('Legacy parameter based assets ', () => { + test('diff asset hashes', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-snapshot-assets.js', 'xxxxx.test-with-snapshot-assets-diff.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({ + reason: DiagnosticReason.SNAPSHOT_FAILED, + testName: 'xxxxx.test-with-snapshot-assets', + message: expect.stringContaining('Parameters'), + config: { diffAssets: true }, + })])); + }); + + test('dont diff asset hashes', () => { + // WHEN + const results = cdkMock.snapshotTest('xxxxx.test-with-snapshot-assets-diff.js', 'xxxxx.test-with-snapshot-assets.js.snapshot'); + + // THEN + expect(results.diagnostics).toEqual([]); + }); + }); + + describe('Legacy Integ Tests', () => { + test('determine test stack via pragma', () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test', + }), + integOutDir: 'does/not/exist', + }); + + // THEN + expect(integTest.actualTests()).toEqual(expect.objectContaining({ + 'xxxxx.integ-test1': { + diffAssets: false, + stackUpdateWorkflow: true, + stacks: ['stack1'], + }, + })); + expect(cdkMock.mocks.list).toHaveBeenCalledTimes(0); + }); + + test('get stacks from list, no pragma', async () => { + // WHEN + const integTest = new IntegSnapshotRunner({ + cdk: cdkMock.cdk, + test: new IntegTest({ + fileName: 'test/test-data/xxxxx.integ-test2.js', + discoveryRoot: 'test', + }), + integOutDir: 'does/not/exist', + }); + + // THEN + expect(integTest.actualTests()).toEqual(expect.objectContaining({ + 'xxxxx.integ-test2': { + diffAssets: false, + stackUpdateWorkflow: true, + stacks: ['stackabc'], + }, + })); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledTimes(1); + expect(cdkMock.mocks.synthFast).toHaveBeenCalledWith({ + execCmd: ['node', 'xxxxx.integ-test2.js'], + env: expect.objectContaining({ + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + }), + output: '../../does/not/exist', + }); + }); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/test-data/assets/code-asset/.keep b/packages/@aws-cdk/integ-runner/test/test-data/assets/code-asset/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.integ-test1.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.integ-test1.js.snapshot/integ.json new file mode 100644 index 000000000..c07eabcac --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.integ-test1.js.snapshot/integ.json @@ -0,0 +1,8 @@ +{ + "version": "v19.0.0", + "testCases": { + "xxxxx.integ-test1": { + "stacks": ["stack1"] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json @@ -0,0 +1 @@ +{} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/integ.json new file mode 100644 index 000000000..c0acf5e47 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-new-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json new file mode 100644 index 000000000..131dfb43e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json @@ -0,0 +1,43 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..fce044c48 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "17.0.0", + "files": { + "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92825": { + "source": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "DIFFERENT_NESTED_STACK_HASH": { + "source": { + "path": "SomeNestedStackResourceA7AEBA6B.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "DIFFERENT_NESTED_STACK_HASH.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..8cd369391 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json @@ -0,0 +1,55 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Key": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92825.zip" + }, + "Role": { + "Fn::GetAtt": ["MyFunction1ServiceRole9852B06B", "Arn"] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": ["MyFunction1ServiceRole9852B06B"] + }, + "SomeNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.unknown-region.amazonaws.com/cdk-hnb659fds-assets-unknown-account-unknown-region/DIFFERENT_NESTED_STACK_HASH.json" + } + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets-diff.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json @@ -0,0 +1 @@ +{} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/integ.json new file mode 100644 index 000000000..d8b60d982 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-new-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": false, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/manifest.json new file mode 100644 index 000000000..131dfb43e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/manifest.json @@ -0,0 +1,43 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..0dd89136d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "17.0.0", + "files": { + "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824": { + "source": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9": { + "source": { + "path": "SomeNestedStackResourceA7AEBA6B.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..8abdf2361 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Key": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + }, + "SomeNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.unknown-region.amazonaws.com/cdk-hnb659fds-assets-unknown-account-unknown-region/6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9.json" + } + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-new-assets.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/integ.json new file mode 100644 index 000000000..126b54791 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/integ.json @@ -0,0 +1,19 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-snapshot-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": false, + "hooks": { + "preDeploy": ["echo \"preDeploy hook\"", "ls", "echo -n \"No new line\""], + "postDeploy": ["echo \"postDeploy hook\""], + "preDestroy": ["echo \"preDestroy hook\""], + "postDestroy": ["echo \"postDestroy hook\""] + }, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json new file mode 100644 index 000000000..818790c0c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json @@ -0,0 +1,73 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/asset1": [ + { + "type": "aws:cdk:asset", + "data": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824" + } + } + ], + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..969780cdf --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + }, + "Parameters": { + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { + "Type": "String", + "Description": "S3 bucket for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { + "Type": "String", + "Description": "S3 key for asset version \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { + "Type": "String", + "Description": "Artifact hash for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot-assets.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/integ.json new file mode 100644 index 000000000..f9d5c63c8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-snapshot": { + "stacks": ["test-stack", "new-test-stack"], + "assertionStack": "Bundling/DefaultTest/DeployAssert", + "assertionStackName": "BundlingDefaultTestDeployAssertAACA0CAF", + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/manifest.json new file mode 100644 index 000000000..3a9c1a23b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "new-test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "new-test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/new-test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/new-test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/new-test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/new-test-stack.template.json new file mode 100644 index 000000000..40f4c8238 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/new-test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..40f4c8238 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json @@ -0,0 +1,54 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/cdk-integ.out.xxxxx.test-with-snapshot.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/not.integ-test.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.js b/packages/@aws-cdk/integ-runner/test/test-data/not.integ-test.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test1.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test1.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test1.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test1.js new file mode 100644 index 000000000..fa2f70554 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test1.js @@ -0,0 +1 @@ +/// !cdk-integ stack1 diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test2.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test2.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test2.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test2.js new file mode 100644 index 000000000..bb0eb24f2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.integ-test2.js @@ -0,0 +1 @@ +/// !cdk-integ pragma:enable-lookups diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json new file mode 100644 index 000000000..914888867 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json new file mode 100644 index 000000000..ad9d0fb73 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/cdk.out new file mode 100644 index 000000000..8ecc185e9 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/integ.json new file mode 100644 index 000000000..0e800e1a3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/integ.json @@ -0,0 +1,11 @@ +{ + "version": "21.0.0", + "testCases": { + "TestWithNestedStack/DefaultTest": { + "stacks": ["test-stack"], + "diffAssets": true, + "assertionStack": "TestWithNestedStack/DefaultTest/DeployAssert", + "assertionStackName": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/manifest.json new file mode 100644 index 000000000..e45aa1d70 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "21.0.0", + "artifacts": { + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.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}/e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "test-stack.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": [ + "test-stack.assets" + ], + "metadata": { + "/test-stack/MyFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunctionServiceRole3C357FF2" + } + ], + "/test-stack/MyFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction3BAA72D1" + } + ], + "/test-stack/nested/MyTopic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTopic86869434" + } + ], + "/test-stack/nested/MyNestedFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionServiceRole56B518B8" + } + ], + "/test-stack/nested/MyNestedFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionA0269B76" + } + ], + "/test-stack/nested.NestedStack/nested.NestedStackResource": [ + { + "type": "aws:cdk:logicalId", + "data": "nestedNestedStacknestedNestedStackResource3DD143BF" + } + ], + "/test-stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/test-stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "test-stack" + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets" + ], + "metadata": { + "/TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TestWithNestedStack/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TestWithNestedStack/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/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..06cae3411 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "21.0.0", + "files": { + "CHANGED_ASSET_HASH": { + "source": { + "path": "asset.CHANGED_ASSET_HASH", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "CHANGED_ASSET_HASH.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234": { + "source": { + "path": "teststacknested140612C4.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..7418c1ab3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/test-stack.template.json @@ -0,0 +1,115 @@ +{ + "Resources": { + "MyFunctionServiceRole3C357FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction3BAA72D1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunctionServiceRole3C357FF2" + ] + }, + "nestedNestedStacknestedNestedStackResource3DD143BF": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json new file mode 100644 index 000000000..0e7b67cd2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json @@ -0,0 +1,63 @@ +{ + "Resources": { + "MyTopic86869434": { + "Type": "AWS::SNS::Topic", + "Properties": { + "DisplayName": "MyTopic" + } + }, + "MyNestedFunctionServiceRole56B518B8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyNestedFunctionA0269B76": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "CHANGED_ASSET_HASH.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyNestedFunctionServiceRole56B518B8" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/tree.json new file mode 100644 index 000000000..8597834c8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-asset-in-nested-stack.js.snapshot/tree.json @@ -0,0 +1,387 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction": { + "id": "MyFunction", + "path": "test-stack/MyFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/MyFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "nested": { + "id": "nested", + "path": "test-stack/nested", + "children": { + "MyTopic": { + "id": "MyTopic", + "path": "test-stack/nested/MyTopic", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/nested/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" + } + }, + "MyNestedFunction": { + "id": "MyNestedFunction", + "path": "test-stack/nested/MyNestedFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "test-stack/nested/MyNestedFunction/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "test-stack/nested/MyNestedFunction/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "test-stack/nested/MyNestedFunction/Code/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68.zip" + }, + "role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.NestedStack", + "version": "0.0.0" + } + }, + "nested.NestedStack": { + "id": "nested.NestedStack", + "path": "test-stack/nested.NestedStack", + "children": { + "nested.NestedStackResource": { + "id": "nested.NestedStackResource", + "path": "test-stack/nested.NestedStack/nested.NestedStackResource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFormation::Stack", + "aws:cdk:cloudformation:props": { + "templateUrl": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnStack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "test-stack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "test-stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "TestWithNestedStack": { + "id": "TestWithNestedStack", + "path": "TestWithNestedStack", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "TestWithNestedStack/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "TestWithNestedStack/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "TestWithNestedStack/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestWithNestedStack/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.154" + } + } + }, + "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/test-data/xxxxx.test-with-error.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-error.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-error.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-error.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-error.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json new file mode 100644 index 000000000..914888867 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json new file mode 100644 index 000000000..ad9d0fb73 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/cdk.out new file mode 100644 index 000000000..8ecc185e9 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/integ.json new file mode 100644 index 000000000..56b2c82cb --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "TestWithNestedStack/DefaultTest": { + "stacks": [ + "test-stack" + ], + "assertionStack": "TestWithNestedStack/DefaultTest/DeployAssert", + "assertionStackName": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/manifest.json new file mode 100644 index 000000000..e45aa1d70 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "21.0.0", + "artifacts": { + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.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}/e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "test-stack.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": [ + "test-stack.assets" + ], + "metadata": { + "/test-stack/MyFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunctionServiceRole3C357FF2" + } + ], + "/test-stack/MyFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction3BAA72D1" + } + ], + "/test-stack/nested/MyTopic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTopic86869434" + } + ], + "/test-stack/nested/MyNestedFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionServiceRole56B518B8" + } + ], + "/test-stack/nested/MyNestedFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionA0269B76" + } + ], + "/test-stack/nested.NestedStack/nested.NestedStackResource": [ + { + "type": "aws:cdk:logicalId", + "data": "nestedNestedStacknestedNestedStackResource3DD143BF" + } + ], + "/test-stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/test-stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "test-stack" + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets" + ], + "metadata": { + "/TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TestWithNestedStack/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TestWithNestedStack/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/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..06cae3411 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "21.0.0", + "files": { + "CHANGED_ASSET_HASH": { + "source": { + "path": "asset.CHANGED_ASSET_HASH", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "CHANGED_ASSET_HASH.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234": { + "source": { + "path": "teststacknested140612C4.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..7418c1ab3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/test-stack.template.json @@ -0,0 +1,115 @@ +{ + "Resources": { + "MyFunctionServiceRole3C357FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction3BAA72D1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunctionServiceRole3C357FF2" + ] + }, + "nestedNestedStacknestedNestedStackResource3DD143BF": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/teststacknested140612C4.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/teststacknested140612C4.nested.template.json new file mode 100644 index 000000000..0e7b67cd2 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/teststacknested140612C4.nested.template.json @@ -0,0 +1,63 @@ +{ + "Resources": { + "MyTopic86869434": { + "Type": "AWS::SNS::Topic", + "Properties": { + "DisplayName": "MyTopic" + } + }, + "MyNestedFunctionServiceRole56B518B8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyNestedFunctionA0269B76": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "CHANGED_ASSET_HASH.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyNestedFunctionServiceRole56B518B8" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/tree.json new file mode 100644 index 000000000..8597834c8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack-changed.js.snapshot/tree.json @@ -0,0 +1,387 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction": { + "id": "MyFunction", + "path": "test-stack/MyFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/MyFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "nested": { + "id": "nested", + "path": "test-stack/nested", + "children": { + "MyTopic": { + "id": "MyTopic", + "path": "test-stack/nested/MyTopic", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/nested/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" + } + }, + "MyNestedFunction": { + "id": "MyNestedFunction", + "path": "test-stack/nested/MyNestedFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "test-stack/nested/MyNestedFunction/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "test-stack/nested/MyNestedFunction/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "test-stack/nested/MyNestedFunction/Code/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68.zip" + }, + "role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.NestedStack", + "version": "0.0.0" + } + }, + "nested.NestedStack": { + "id": "nested.NestedStack", + "path": "test-stack/nested.NestedStack", + "children": { + "nested.NestedStackResource": { + "id": "nested.NestedStackResource", + "path": "test-stack/nested.NestedStack/nested.NestedStackResource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFormation::Stack", + "aws:cdk:cloudformation:props": { + "templateUrl": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnStack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "test-stack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "test-stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "TestWithNestedStack": { + "id": "TestWithNestedStack", + "path": "TestWithNestedStack", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "TestWithNestedStack/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "TestWithNestedStack/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "TestWithNestedStack/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestWithNestedStack/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.154" + } + } + }, + "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/test-data/xxxxx.test-with-nested-stack.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json new file mode 100644 index 000000000..914888867 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.template.json new file mode 100644 index 000000000..ad9d0fb73 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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/test-data/xxxxx.test-with-nested-stack.js.snapshot/asset.b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68/.keep b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/asset.b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/cdk.out new file mode 100644 index 000000000..8ecc185e9 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/integ.json new file mode 100644 index 000000000..56b2c82cb --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "TestWithNestedStack/DefaultTest": { + "stacks": [ + "test-stack" + ], + "assertionStack": "TestWithNestedStack/DefaultTest/DeployAssert", + "assertionStackName": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/manifest.json new file mode 100644 index 000000000..e45aa1d70 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "21.0.0", + "artifacts": { + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.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}/e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "test-stack.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": [ + "test-stack.assets" + ], + "metadata": { + "/test-stack/MyFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunctionServiceRole3C357FF2" + } + ], + "/test-stack/MyFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction3BAA72D1" + } + ], + "/test-stack/nested/MyTopic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTopic86869434" + } + ], + "/test-stack/nested/MyNestedFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionServiceRole56B518B8" + } + ], + "/test-stack/nested/MyNestedFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyNestedFunctionA0269B76" + } + ], + "/test-stack/nested.NestedStack/nested.NestedStackResource": [ + { + "type": "aws:cdk:logicalId", + "data": "nestedNestedStacknestedNestedStackResource3DD143BF" + } + ], + "/test-stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/test-stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "test-stack" + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.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": [ + "TestWithNestedStackDefaultTestDeployAssert9F80D3B6.assets" + ], + "metadata": { + "/TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TestWithNestedStack/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TestWithNestedStack/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/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..9232e135e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "21.0.0", + "files": { + "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68": { + "source": { + "path": "asset.b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234": { + "source": { + "path": "teststacknested140612C4.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "e329bc2347c70a89ff078c2c93444d2b59a21f04cbf91afff7e9e5cab307b381.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/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..7418c1ab3 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/test-stack.template.json @@ -0,0 +1,115 @@ +{ + "Resources": { + "MyFunctionServiceRole3C357FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction3BAA72D1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunctionServiceRole3C357FF2" + ] + }, + "nestedNestedStacknestedNestedStackResource3DD143BF": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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/test-data/xxxxx.test-with-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json new file mode 100644 index 000000000..68c6227f9 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/teststacknested140612C4.nested.template.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "MyTopic86869434": { + "Type": "AWS::SNS::Topic" + }, + "MyNestedFunctionServiceRole56B518B8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyNestedFunctionA0269B76": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyNestedFunctionServiceRole56B518B8" + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/tree.json new file mode 100644 index 000000000..8597834c8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-nested-stack.js.snapshot/tree.json @@ -0,0 +1,387 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction": { + "id": "MyFunction", + "path": "test-stack/MyFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/MyFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunctionServiceRole3C357FF2", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "nested": { + "id": "nested", + "path": "test-stack/nested", + "children": { + "MyTopic": { + "id": "MyTopic", + "path": "test-stack/nested/MyTopic", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/nested/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" + } + }, + "MyNestedFunction": { + "id": "MyNestedFunction", + "path": "test-stack/nested/MyNestedFunction", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "test-stack/nested/MyNestedFunction/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "test-stack/nested/MyNestedFunction/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "test-stack/nested/MyNestedFunction/Code/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/nested/MyNestedFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "b7826d21185e020066e56b133136e1082372d08cf21209a8823ac39710782f68.zip" + }, + "role": { + "Fn::GetAtt": [ + "MyNestedFunctionServiceRole56B518B8", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.NestedStack", + "version": "0.0.0" + } + }, + "nested.NestedStack": { + "id": "nested.NestedStack", + "path": "test-stack/nested.NestedStack", + "children": { + "nested.NestedStackResource": { + "id": "nested.NestedStackResource", + "path": "test-stack/nested.NestedStack/nested.NestedStackResource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudFormation::Stack", + "aws:cdk:cloudformation:props": { + "templateUrl": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/68d244d71d1a0f2942feda5bea8f07b26ee3b09b4e9df7eac4296dcaf8532234.json" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnStack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "test-stack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "test-stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "TestWithNestedStack": { + "id": "TestWithNestedStack", + "path": "TestWithNestedStack", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "TestWithNestedStack/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "TestWithNestedStack/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.154" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "TestWithNestedStack/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestWithNestedStack/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestWithNestedStack/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.154" + } + } + }, + "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/test-data/xxxxx.test-with-new-assets-diff.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json @@ -0,0 +1 @@ +{} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js new file mode 100755 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/integ.json new file mode 100644 index 000000000..c0acf5e47 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-new-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json new file mode 100644 index 000000000..131dfb43e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/manifest.json @@ -0,0 +1,43 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..fce044c48 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "17.0.0", + "files": { + "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92825": { + "source": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "DIFFERENT_NESTED_STACK_HASH": { + "source": { + "path": "SomeNestedStackResourceA7AEBA6B.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "DIFFERENT_NESTED_STACK_HASH.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..d564a1f01 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/test-stack.template.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Key": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92825.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + }, + "SomeNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.unknown-region.amazonaws.com/cdk-hnb659fds-assets-unknown-account-unknown-region/DIFFERENT_NESTED_STACK_HASH.json" + } + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets-diff.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/xxxxx.test-with-new-assets.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/SomeNestedStackResourceA7AEBA6B.nested.template.json @@ -0,0 +1 @@ +{} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js new file mode 100755 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/integ.json new file mode 100644 index 000000000..c0acf5e47 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-new-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/manifest.json new file mode 100644 index 000000000..131dfb43e --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/manifest.json @@ -0,0 +1,43 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..0dd89136d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "17.0.0", + "files": { + "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824": { + "source": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9": { + "source": { + "path": "SomeNestedStackResourceA7AEBA6B.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..8abdf2361 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/test-stack.template.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Key": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + }, + "SomeNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.unknown-region.amazonaws.com/cdk-hnb659fds-assets-unknown-account-unknown-region/6f980d09d47a00a7d5001feeb3994d1909bc5294e309d69bd4fbc815622f6fa9.json" + } + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-new-assets.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/xxxxx.test-with-snapshot-assets-diff.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js new file mode 100644 index 000000000..8546bc895 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack pragma:enable-lookups pragma:disable-update-workflow diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/asset.fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509/index.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/asset.fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/integ.json new file mode 100644 index 000000000..c602dbd38 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "enableLookups": true, + "xxxxx.test-with-snapshot-assets-diff": { + "stacks": ["test-stack"], + "diffAssets": false, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/manifest.json new file mode 100644 index 000000000..0d7e598bc --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/manifest.json @@ -0,0 +1,49 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack": [ + { + "type": "aws:cdk:asset", + "data": { + "path": "asset.fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509", + "id": "fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509", + "packaging": "zip", + "sourceHash": "fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509", + "s3BucketParameter": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C", + "s3KeyParameter": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1", + "artifactHashParameter": "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B" + } + } + ], + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..969780cdf --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/test-stack.template.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + }, + "Parameters": { + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { + "Type": "String", + "Description": "S3 bucket for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { + "Type": "String", + "Description": "S3 key for asset version \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersDec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { + "Type": "String", + "Description": "Artifact hash for asset \"Dec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets-diff.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/xxxxx.test-with-snapshot-assets.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js new file mode 100644 index 000000000..ff230f9f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack pragma:include-assets-hashes diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/integ.json new file mode 100644 index 000000000..0b7245895 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-snapshot-assets": { + "stacks": ["test-stack"], + "stackUpdateWorkflow": false, + "diffAssets": false, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json new file mode 100644 index 000000000..606c37571 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/manifest.json @@ -0,0 +1,43 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.assets.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.assets.json new file mode 100644 index 000000000..9fce39f0c --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.assets.json @@ -0,0 +1,32 @@ +{ + "version": "17.0.0", + "files": { + "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824": { + "source": { + "path": "asset.be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "be270bbdebe0851c887569796e3997437cca54ce86893ed94788500448e92824.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cb05f22f001734dbadeb4f07d875c6ab8180f703346a8d66fca572a0e94c54a9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..ed2a09b94 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/test-stack.template.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + }, + "Parameters": { + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3BucketBF50F97C": { + "Type": "String", + "Description": "S3 bucket for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509S3VersionKeyF21AC8C1": { + "Type": "String", + "Description": "S3 key for asset version \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + }, + "AssetParametersfec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509ArtifactHash5D8C129B": { + "Type": "String", + "Description": "Artifact hash for asset \"fec1c56a3f23d9d27f58815e0c34c810cc02f431ac63a078f9b5d2aa44cc3509\"" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-assets.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/integ.json new file mode 100644 index 000000000..25baeac58 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-snapshot": { + "stacks": ["test-stack"], + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/manifest.json new file mode 100644 index 000000000..c0da3afe1 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/manifest.json @@ -0,0 +1,57 @@ +{ + "version": "17.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B", + "trace": [ + "new Role (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-iam/lib/role.js:50:22)", + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:82:35)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E", + "trace": [ + "new Function (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-lambda/lib/function.js:154:26)", + "new TestStack (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:10:9)", + "Object. (/home/hallcor/work/aws-cdk/integ-test-runner/packages/@aws-cdk/aws-s3objectlambda/test/integ.lambda.js:18:1)", + "Module._compile (node:internal/modules/cjs/loader:1103:14)", + "Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)", + "Module.load (node:internal/modules/cjs/loader:981:32)", + "Function.Module._load (node:internal/modules/cjs/loader:822:12)", + "Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)", + "node:internal/main/run_main_module:17:47" + ] + } + ] + }, + "displayName": "test-stack" + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..0fe046e1b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/test-stack.template.json @@ -0,0 +1,75 @@ +{ + "Resources": { + "MyFunction2ServiceRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyLambdaFuncServiceRoleDefaultPolicy": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyLambdaFuncServiceRoleDefaultPolicyBEB0E748", + "Roles": [ + { + "Ref": "MyLambdaFuncServiceRole" + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foobar" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot-diff.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/test-data/xxxxx.test-with-snapshot.d.ts b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js new file mode 100644 index 000000000..e43a408f7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js @@ -0,0 +1 @@ +/// !cdk-integ test-stack diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/cdk.out b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/cdk.out new file mode 100644 index 000000000..2efc89439 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"18.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/integ.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/integ.json new file mode 100644 index 000000000..8d0b1a406 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "v1.0.0", + "testCases": { + "xxxxx.test-with-snapshot": { + "stacks": ["test-stack"], + "assertionStack": "Bundling/DefaultTest/DeployAssert", + "assertionStackName": "BundlingDefaultTestDeployAssertAACA0CAF", + "diffAssets": true, + "allowDestroy": [ + "AWS::IAM::Role" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/manifest.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/manifest.json new file mode 100644 index 000000000..5c9fd61ec --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/manifest.json @@ -0,0 +1,58 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + }, + "metadata": {} + }, + "test-stack-do-not-diff": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack-do-not-diff.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack-do-not-diff/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack-do-not-diff/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack-do-not-diff" + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/MyFunction1/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction1ServiceRole9852B06B" + } + ], + "/test-stack/MyFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunction12A744C2E" + } + ] + }, + "displayName": "test-stack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack-do-not-diff.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack-do-not-diff.template.json new file mode 100644 index 000000000..efed158f8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack-do-not-diff.template.json @@ -0,0 +1,75 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyLambdaFuncServiceRoleDefaultPolicyBEB0E748": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyLambdaFuncServiceRoleDefaultPolicyBEB0E748", + "Roles": [ + { + "Ref": "MyFunction1ServiceRole9852B06B" + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json new file mode 100644 index 000000000..efed158f8 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/test-stack.template.json @@ -0,0 +1,75 @@ +{ + "Resources": { + "MyFunction1ServiceRole9852B06B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyLambdaFuncServiceRoleDefaultPolicyBEB0E748": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyLambdaFuncServiceRoleDefaultPolicyBEB0E748", + "Roles": [ + { + "Ref": "MyFunction1ServiceRole9852B06B" + } + ] + } + }, + "MyFunction12A744C2E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "MyFunction1ServiceRole9852B06B" + ] + } + } +} diff --git a/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/tree.json b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/tree.json new file mode 100644 index 000000000..b664bec74 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/test-data/xxxxx.test-with-snapshot.js.snapshot/tree.json @@ -0,0 +1,114 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "@aws-cdk/core.Construct", + "version": "0.0.0" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "MyFunction1": { + "id": "MyFunction1", + "path": "test-stack/MyFunction1", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "test-stack/MyFunction1/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/MyFunction1/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "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": "test-stack/MyFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "zipFile": "foo" + }, + "role": { + "Fn::GetAtt": [ + "MyFunction1ServiceRole9852B06B", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs14.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "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/workers/integ-worker.test.ts b/packages/@aws-cdk/integ-runner/test/workers/integ-worker.test.ts new file mode 100644 index 000000000..eb92c8f0d --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/workers/integ-worker.test.ts @@ -0,0 +1,516 @@ +import * as child_process from 'child_process'; +import * as builtinFs from 'fs'; +import * as path from 'path'; +import * as fs from 'fs-extra'; +import * as workerpool from 'workerpool'; +import { integTestWorker } from '../../lib/workers/extract'; +import { runIntegrationTestsInParallel, runIntegrationTests } from '../../lib/workers/integ-test-worker'; +let stderrMock: jest.SpyInstance; +let pool: workerpool.WorkerPool; +let spawnSyncMock: jest.SpyInstance; +beforeAll(() => { + pool = workerpool.pool(path.join(__dirname, 'mock-extract_worker.ts'), { + workerType: 'thread', + workerThreadOpts: { + execArgv: ['--require', 'ts-node/register'], + }, + }); +}); +beforeEach(() => { + jest.spyOn(fs, 'moveSync').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'emptyDirSync').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { + return true; + }); + + // fs-extra delegates to the built-in one, this also catches calls done directly + jest.spyOn(builtinFs, 'rmdirSync').mockImplementation(() => { + return true; + }); + jest.spyOn(builtinFs, 'writeFileSync').mockImplementation(() => { + return true; + }); + jest.spyOn(builtinFs, 'unlinkSync').mockImplementation(() => { + return true; + }); + + spawnSyncMock = jest.spyOn(child_process, 'spawnSync') + .mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('sdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }) + .mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('HEAD branch: master\nother'), + stdout: Buffer.from('HEAD branch: master\nother'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }).mockReturnValueOnce({ + status: 0, + stderr: Buffer.from('abc'), + stdout: Buffer.from('abc'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }).mockReturnValue({ + status: 0, + stderr: Buffer.from('stack1'), + stdout: Buffer.from('stack1'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { + return true; + }); +}); +afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); +}); +afterAll(async () => { + await pool.terminate(); +}); + +describe('test runner', () => { + test('no snapshot', () => { + // WHEN + const test = { + fileName: 'test/test-data/xxxxx.integ-test1.js', + discoveryRoot: 'test/test-data', + }; + integTestWorker({ + tests: [test], + region: 'us-east-1', + }); + + expect(spawnSyncMock).toHaveBeenCalledWith( + expect.stringMatching(/node/), + ['xxxxx.integ-test1.js'], + expect.objectContaining({ + env: expect.objectContaining({ + CDK_INTEG_ACCOUNT: '12345678', + CDK_INTEG_REGION: 'test-region', + }), + }), + ); + }); + + test('legacy test throws', () => { + // WHEN + const test = { + fileName: 'test/test-data/xxxxx.integ-test2.js', + discoveryRoot: 'test/test-data', + }; + spawnSyncMock.mockReset(); + jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('test-stack'), + stdout: Buffer.from('test-stack'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + // GIVEN + const results = integTestWorker({ + tests: [test], + region: 'us-east-1', + }); + + // THEN + expect(results).toEqual([{ + discoveryRoot: 'test/test-data', + fileName: 'test/test-data/xxxxx.integ-test2.js', + }]); + }); + + test('has snapshot', () => { + // WHEN + const test = { + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }; + const results = integTestWorker({ + tests: [test], + region: 'us-east-3', + }); + + expect(spawnSyncMock.mock.calls).toEqual(expect.arrayContaining([ + expect.arrayContaining([ + expect.stringMatching(/git/), + ['remote', 'show', 'origin'], + expect.objectContaining({ + cwd: 'test/test-data', + }), + ]), + expect.arrayContaining([ + expect.stringMatching(/git/), + ['merge-base', 'HEAD', 'master'], + expect.objectContaining({ + cwd: 'test/test-data', + }), + ]), + expect.arrayContaining([ + expect.stringMatching(/git/), + ['checkout', 'abc', '--', 'xxxxx.test-with-snapshot.js.snapshot'], + expect.objectContaining({ + cwd: 'test/test-data', + }), + ]), + ])); + + expect(results).toEqual([]); + }); + + test('deploy failed', () => { + // WHEN + const test = { + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }; + jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 1, + stderr: Buffer.from('stack1'), + stdout: Buffer.from('stack1'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const results = integTestWorker({ + tests: [test], + region: 'us-east-1', + }); + + expect(results[0]).toEqual({ + fileName: 'test/test-data/xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }); + }); +}); + +describe('parallel worker', () => { + test('run all integration tests', async () => { + const tests = [ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]; + await runIntegrationTests({ + tests, + pool, + regions: ['us-east-1', 'us-east-2'], + }); + + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running integration tests for failed tests...', + ); + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running in parallel across regions: us-east-1, us-east-2', + ); + expect(stderrMock.mock.calls[2][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot.js in us-east-1', + ); + expect(stderrMock.mock.calls[3][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in us-east-2', + ); + }); + + test('run tests', async () => { + const tests = [{ + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }]; + const results = await runIntegrationTestsInParallel({ + pool, + tests, + regions: ['us-east-1'], + }); + + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual({ + failedTests: expect.arrayContaining([ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]), + metrics: expect.arrayContaining([ + { + duration: expect.anything(), + region: 'us-east-1', + tests: { + 'xxxxx.test-with-snapshot.js': expect.anything(), + }, + }, + ]), + }); + }); + + test('run multiple tests with profiles', async () => { + const tests = [ + { + fileName: 'xxxxx.another-test-with-snapshot3.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot2.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + profiles: ['profile1', 'profile2'], + regions: ['us-east-1', 'us-east-2'], + }); + + expect(stderrMock.mock.calls[3][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot3.js in profile2/us-east-2', + ); + expect(stderrMock.mock.calls[2][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot2.js in profile2/us-east-1', + ); + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot.js in profile1/us-east-2', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in profile1/us-east-1', + ); + expect(results).toEqual({ + failedTests: expect.arrayContaining([ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot2.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot3.js', + discoveryRoot: 'test/test-data', + }, + ]), + metrics: expect.arrayContaining([ + { + duration: expect.any(Number), + region: 'us-east-1', + profile: 'profile1', + tests: { + 'xxxxx.test-with-snapshot.js': expect.any(Number), + }, + }, + { + duration: expect.any(Number), + region: 'us-east-2', + profile: 'profile1', + tests: { + 'xxxxx.another-test-with-snapshot.js': expect.any(Number), + }, + }, + { + duration: expect.any(Number), + region: 'us-east-1', + profile: 'profile2', + tests: { + 'xxxxx.another-test-with-snapshot2.js': expect.any(Number), + }, + }, + { + duration: expect.any(Number), + region: 'us-east-2', + profile: 'profile2', + tests: { + 'xxxxx.another-test-with-snapshot3.js': expect.any(Number), + }, + }, + ]), + }); + }); + + test('run multiple tests', async () => { + const tests = [ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1', 'us-east-2'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in us-east-2', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual({ + failedTests: expect.arrayContaining([ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]), + metrics: expect.arrayContaining([ + { + duration: expect.anything(), + region: 'us-east-2', + tests: { + 'xxxxx.test-with-snapshot.js': expect.anything(), + }, + }, + { + duration: expect.anything(), + region: 'us-east-1', + tests: { + 'xxxxx.another-test-with-snapshot.js': expect.anything(), + }, + }, + ]), + }); + }); + + test('more tests than regions', async () => { + const tests = [ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in us-east-1', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual({ + failedTests: expect.arrayContaining([ + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]), + metrics: expect.arrayContaining([ + { + duration: expect.anything(), + region: 'us-east-1', + tests: { + 'xxxxx.test-with-snapshot.js': expect.anything(), + 'xxxxx.another-test-with-snapshot.js': expect.anything(), + }, + }, + ]), + }); + }); + + test('more regions than tests', async () => { + const tests = [ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]; + const results = await runIntegrationTestsInParallel({ + tests, + pool, + regions: ['us-east-1', 'us-east-2', 'us-west-2'], + }); + + expect(stderrMock.mock.calls[1][0]).toContain( + 'Running test xxxxx.test-with-snapshot.js in us-east-2', + ); + expect(stderrMock.mock.calls[0][0]).toContain( + 'Running test xxxxx.another-test-with-snapshot.js in us-east-1', + ); + expect(results).toEqual({ + failedTests: expect.arrayContaining([ + { + fileName: 'xxxxx.test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + { + fileName: 'xxxxx.another-test-with-snapshot.js', + discoveryRoot: 'test/test-data', + }, + ]), + metrics: expect.arrayContaining([ + { + duration: expect.anything(), + region: 'us-east-2', + tests: { + 'xxxxx.test-with-snapshot.js': expect.anything(), + }, + }, + { + duration: expect.anything(), + region: 'us-east-1', + tests: { + 'xxxxx.another-test-with-snapshot.js': expect.anything(), + }, + }, + ]), + }); + }); +}); diff --git a/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts b/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts new file mode 100644 index 000000000..5d390a13b --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/workers/mock-extract_worker.ts @@ -0,0 +1,12 @@ +import * as workerpool from 'workerpool'; +import type { IntegTestInfo } from '../../lib/runner'; +import type { IntegTestBatchRequest } from '../../lib/workers/integ-test-worker'; + +function integTestWorker(request: IntegTestBatchRequest): IntegTestInfo[] { + return request.tests; +} + +workerpool.worker({ + integTestWorker, +}); + diff --git a/packages/@aws-cdk/integ-runner/test/workers/snapshot-worker.test.ts b/packages/@aws-cdk/integ-runner/test/workers/snapshot-worker.test.ts new file mode 100644 index 000000000..f166dddbf --- /dev/null +++ b/packages/@aws-cdk/integ-runner/test/workers/snapshot-worker.test.ts @@ -0,0 +1,69 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; +import { snapshotTestWorker } from '../../lib/workers/extract'; + +beforeEach(() => { + jest.spyOn(process.stderr, 'write').mockImplementation(() => { + return true; + }); + jest.spyOn(process.stdout, 'write').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'moveSync').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'removeSync').mockImplementation(() => { + return true; + }); + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => { + return true; + }); +}); +afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + jest.restoreAllMocks(); +}); + +const directory = path.join(__dirname, '..', 'test-data'); +describe('Snapshot tests', () => { + test('no snapshot', () => { + // WHEN + const test = { + fileName: path.join(directory, 'xxxxx.integ-test1.js'), + discoveryRoot: directory, + }; + const result = snapshotTestWorker(test); + + // THEN + expect(result.length).toEqual(1); + expect(result[0]).toEqual(test); + }); + + test('has snapshot', () => { + // WHEN + const test = { + fileName: path.join(directory, 'xxxxx.test-with-snapshot.js'), + discoveryRoot: directory, + }; + const result = snapshotTestWorker(test); + + // THEN + expect(result.length).toEqual(1); + }); + + test('failed snapshot', () => { + // WHEN + const test = { + fileName: path.join(directory, 'xxxxx.test-with-snapshot-assets-diff.js'), + discoveryRoot: directory, + destructiveChanges: [], + }; + const result = snapshotTestWorker(test); + + // THEN + expect(result.length).toEqual(1); + expect(result[0]).toEqual(test); + }); +}); + diff --git a/packages/@aws-cdk/integ-runner/tsconfig.dev.json b/packages/@aws-cdk/integ-runner/tsconfig.dev.json new file mode 100644 index 000000000..3fb9f8e25 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/tsconfig.dev.json @@ -0,0 +1,57 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "compilerOptions": { + "alwaysStrict": true, + "declaration": true, + "esModuleInterop": false, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "es2020", + "dom" + ], + "module": "commonjs", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, + "composite": true, + "outDir": "lib" + }, + "include": [ + "lib/**/*.ts", + "test/**/*.ts" + ], + "exclude": [ + "node_modules" + ], + "references": [ + { + "path": "../cloud-assembly-schema" + }, + { + "path": "../cdk-cli-wrapper" + }, + { + "path": "../../aws-cdk" + }, + { + "path": "../../cdk-assets" + }, + { + "path": "../cloudformation-diff" + } + ] +} diff --git a/packages/@aws-cdk/integ-runner/tsconfig.json b/packages/@aws-cdk/integ-runner/tsconfig.json new file mode 100644 index 000000000..5a9c6f5a7 --- /dev/null +++ b/packages/@aws-cdk/integ-runner/tsconfig.json @@ -0,0 +1,60 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "compilerOptions": { + "rootDir": "lib", + "outDir": "lib", + "alwaysStrict": true, + "declaration": true, + "esModuleInterop": false, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "es2020", + "dom" + ], + "module": "commonjs", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, + "composite": true + }, + "include": [ + "lib/**/*.ts", + "lib/*.json", + "lib/init-templates/*/*/add-project.hook.ts" + ], + "exclude": [ + "lib/init-templates/*/typescript/**/*.ts", + "test/language-tests/**/integ.*.ts" + ], + "references": [ + { + "path": "../cloud-assembly-schema" + }, + { + "path": "../cdk-cli-wrapper" + }, + { + "path": "../../aws-cdk" + }, + { + "path": "../../cdk-assets" + }, + { + "path": "../cloudformation-diff" + } + ] +} diff --git a/packages/@aws-cdk/node-bundle/.projen/deps.json b/packages/@aws-cdk/node-bundle/.projen/deps.json index b4a3b1ed0..eac6ff801 100644 --- a/packages/@aws-cdk/node-bundle/.projen/deps.json +++ b/packages/@aws-cdk/node-bundle/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/node-bundle/.projen/tasks.json b/packages/@aws-cdk/node-bundle/.projen/tasks.json index 5f398a5b7..45039b899 100644 --- a/packages/@aws-cdk/node-bundle/.projen/tasks.json +++ b/packages/@aws-cdk/node-bundle/.projen/tasks.json @@ -37,7 +37,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,@types/license-checker,@types/madge,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,standard-version,ts-jest,esbuild,license-checker,madge,shlex,yargs" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,@types/license-checker,@types/madge,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,standard-version,ts-jest,esbuild,license-checker,madge,shlex,yargs" } ] }, diff --git a/packages/@aws-cdk/node-bundle/package.json b/packages/@aws-cdk/node-bundle/package.json index ffddb4c84..46f3dbe54 100644 --- a/packages/@aws-cdk/node-bundle/package.json +++ b/packages/@aws-cdk/node-bundle/package.json @@ -34,7 +34,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/fs-extra": "^9", "@types/jest": "^29.5.14", "@types/license-checker": "^25.0.6", diff --git a/packages/@aws-cdk/node-bundle/tsconfig.dev.json b/packages/@aws-cdk/node-bundle/tsconfig.dev.json index 3329a3ca8..8c3d5c245 100644 --- a/packages/@aws-cdk/node-bundle/tsconfig.dev.json +++ b/packages/@aws-cdk/node-bundle/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/node-bundle/tsconfig.json b/packages/@aws-cdk/node-bundle/tsconfig.json index e01460c18..1594d817e 100644 --- a/packages/@aws-cdk/node-bundle/tsconfig.json +++ b/packages/@aws-cdk/node-bundle/tsconfig.json @@ -5,14 +5,15 @@ "outDir": "lib", "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/.projen/deps.json b/packages/@aws-cdk/tmp-toolkit-helpers/.projen/deps.json index 5dfc8c071..ce84472f3 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/.projen/deps.json +++ b/packages/@aws-cdk/tmp-toolkit-helpers/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/.projen/tasks.json b/packages/@aws-cdk/tmp-toolkit-helpers/.projen/tasks.json index 231f40fad..fad4dd245 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/.projen/tasks.json +++ b/packages/@aws-cdk/tmp-toolkit-helpers/.projen/tasks.json @@ -37,7 +37,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/archiver,@types/jest,@types/semver,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,projen,ts-jest,@aws-cdk/cloud-assembly-schema,archiver,glob,semver,uuid" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/archiver,@types/jest,@types/semver,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,projen,ts-jest,@aws-cdk/cloud-assembly-schema,archiver,glob,semver,uuid" } ] }, diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/package.json b/packages/@aws-cdk/tmp-toolkit-helpers/package.json index 8c3adf945..81435714a 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/package.json +++ b/packages/@aws-cdk/tmp-toolkit-helpers/package.json @@ -31,7 +31,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/archiver": "^6.0.3", "@types/jest": "^29.5.14", "@types/node": "^16", diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.dev.json b/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.dev.json index bc353830b..f1aaa8777 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.dev.json +++ b/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.dev.json @@ -9,7 +9,8 @@ "inlineSources": true, "lib": [ "es2022", - "esnext.disposable" + "esnext.disposable", + "dom" ], "module": "NodeNext", "noEmitOnError": false, @@ -25,6 +26,8 @@ "strictPropertyInitialization": true, "stripInternal": true, "target": "es2022", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.json b/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.json index 84f2e1f2b..9150afdf2 100644 --- a/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.json +++ b/packages/@aws-cdk/tmp-toolkit-helpers/tsconfig.json @@ -11,7 +11,8 @@ "inlineSources": true, "lib": [ "es2022", - "esnext.disposable" + "esnext.disposable", + "dom" ], "module": "NodeNext", "noEmitOnError": false, @@ -27,6 +28,8 @@ "strictPropertyInitialization": true, "stripInternal": true, "target": "es2022", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/@aws-cdk/toolkit-lib/.projen/deps.json b/packages/@aws-cdk/toolkit-lib/.projen/deps.json index 413dca83c..ea7f39a0c 100644 --- a/packages/@aws-cdk/toolkit-lib/.projen/deps.json +++ b/packages/@aws-cdk/toolkit-lib/.projen/deps.json @@ -14,6 +14,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/toolkit-lib/.projen/tasks.json b/packages/@aws-cdk/toolkit-lib/.projen/tasks.json index 439009086..d49a198a3 100644 --- a/packages/@aws-cdk/toolkit-lib/.projen/tasks.json +++ b/packages/@aws-cdk/toolkit-lib/.projen/tasks.json @@ -51,7 +51,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@smithy/types,@stylistic/eslint-plugin,@types/fs-extra,@types/jest,@types/split2,aws-cdk-lib,aws-sdk-client-mock,dts-bundle-generator,esbuild,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest,typedoc,@aws-cdk/cx-api,@aws-cdk/region-info,@smithy/middleware-endpoint,@smithy/node-http-handler,@smithy/property-provider,@smithy/shared-ini-file-loader,@smithy/util-retry,@smithy/util-stream,@smithy/util-waiter,archiver,cdk-from-cfn,glob,json-diff,minimatch,promptly,proxy-agent,semver,split2,uuid" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@smithy/types,@types/fs-extra,@types/jest,@types/split2,aws-cdk-lib,aws-sdk-client-mock,dts-bundle-generator,esbuild,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest,typedoc,@aws-cdk/cx-api,@aws-cdk/region-info,@smithy/middleware-endpoint,@smithy/node-http-handler,@smithy/property-provider,@smithy/shared-ini-file-loader,@smithy/util-retry,@smithy/util-stream,@smithy/util-waiter,archiver,cdk-from-cfn,glob,json-diff,minimatch,promptly,proxy-agent,semver,split2,uuid" } ] }, diff --git a/packages/@aws-cdk/toolkit-lib/package.json b/packages/@aws-cdk/toolkit-lib/package.json index 5f0e37c1a..23cd57e40 100644 --- a/packages/@aws-cdk/toolkit-lib/package.json +++ b/packages/@aws-cdk/toolkit-lib/package.json @@ -37,7 +37,7 @@ "@aws-cdk/tmp-toolkit-helpers": "^0.0.0", "@cdklabs/eslint-plugin": "^1.3.2", "@smithy/types": "^4.1.0", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.14", "@types/node": "^16", diff --git a/packages/@aws-cdk/toolkit-lib/tsconfig.dev.json b/packages/@aws-cdk/toolkit-lib/tsconfig.dev.json index 01c60489f..c92d692df 100644 --- a/packages/@aws-cdk/toolkit-lib/tsconfig.dev.json +++ b/packages/@aws-cdk/toolkit-lib/tsconfig.dev.json @@ -9,7 +9,8 @@ "inlineSources": true, "lib": [ "es2022", - "esnext.disposable" + "esnext.disposable", + "dom" ], "module": "NodeNext", "noEmitOnError": false, @@ -25,6 +26,8 @@ "strictPropertyInitialization": true, "stripInternal": true, "target": "es2022", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/toolkit-lib/tsconfig.json b/packages/@aws-cdk/toolkit-lib/tsconfig.json index 58dfd0f1e..cf064da97 100644 --- a/packages/@aws-cdk/toolkit-lib/tsconfig.json +++ b/packages/@aws-cdk/toolkit-lib/tsconfig.json @@ -11,7 +11,8 @@ "inlineSources": true, "lib": [ "es2022", - "esnext.disposable" + "esnext.disposable", + "dom" ], "module": "NodeNext", "noEmitOnError": false, @@ -27,6 +28,8 @@ "strictPropertyInitialization": true, "stripInternal": true, "target": "es2022", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/@aws-cdk/user-input-gen/.projen/deps.json b/packages/@aws-cdk/user-input-gen/.projen/deps.json index 507226458..8cb76108a 100644 --- a/packages/@aws-cdk/user-input-gen/.projen/deps.json +++ b/packages/@aws-cdk/user-input-gen/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/@aws-cdk/user-input-gen/.projen/tasks.json b/packages/@aws-cdk/user-input-gen/.projen/tasks.json index f63a20167..d139f26aa 100644 --- a/packages/@aws-cdk/user-input-gen/.projen/tasks.json +++ b/packages/@aws-cdk/user-input-gen/.projen/tasks.json @@ -37,7 +37,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,@types/lodash.clonedeep,@types/semver,@types/yarnpkg__lockfile,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,ts-jest,@cdklabs/typewriter,lodash.clonedeep" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,@types/lodash.clonedeep,@types/semver,@types/yarnpkg__lockfile,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,projen,ts-jest,@cdklabs/typewriter,lodash.clonedeep" } ] }, diff --git a/packages/@aws-cdk/user-input-gen/package.json b/packages/@aws-cdk/user-input-gen/package.json index a0f1a644b..292a07fa0 100644 --- a/packages/@aws-cdk/user-input-gen/package.json +++ b/packages/@aws-cdk/user-input-gen/package.json @@ -31,7 +31,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/lodash.clonedeep": "^4.5.9", "@types/node": "^17", diff --git a/packages/@aws-cdk/user-input-gen/tsconfig.dev.json b/packages/@aws-cdk/user-input-gen/tsconfig.dev.json index 18ee3a655..c23fc6c66 100644 --- a/packages/@aws-cdk/user-input-gen/tsconfig.dev.json +++ b/packages/@aws-cdk/user-input-gen/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/@aws-cdk/user-input-gen/tsconfig.json b/packages/@aws-cdk/user-input-gen/tsconfig.json index a9cd6a329..494d42c75 100644 --- a/packages/@aws-cdk/user-input-gen/tsconfig.json +++ b/packages/@aws-cdk/user-input-gen/tsconfig.json @@ -5,14 +5,15 @@ "outDir": "lib", "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/aws-cdk/.projen/deps.json b/packages/aws-cdk/.projen/deps.json index 17f0feea5..a5d36da30 100644 --- a/packages/aws-cdk/.projen/deps.json +++ b/packages/aws-cdk/.projen/deps.json @@ -26,6 +26,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/aws-cdk/.projen/tasks.json b/packages/aws-cdk/.projen/tasks.json index 4ae1c5a19..b9eb50493 100644 --- a/packages/aws-cdk/.projen/tasks.json +++ b/packages/aws-cdk/.projen/tasks.json @@ -52,7 +52,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@octokit/rest,@stylistic/eslint-plugin,@types/archiver,@types/jest,@types/mockery,@types/promptly,@types/semver,@types/sinon,aws-cdk-lib,axios,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,jest-environment-node,jest-mock,license-checker,madge,nock,projen,sinon,ts-jest,ts-mock-imports,xml-js,@aws-cdk/cx-api,@aws-cdk/region-info,@aws-sdk/middleware-endpoint,@aws-sdk/util-retry,@aws-sdk/util-waiter,@smithy/middleware-endpoint,@smithy/property-provider,@smithy/shared-ini-file-loader,@smithy/types,@smithy/util-retry,@smithy/util-stream,@smithy/util-waiter,archiver,glob,minimatch,promptly,proxy-agent,semver,table,uuid" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@octokit/rest,@types/archiver,@types/jest,@types/mockery,@types/promptly,@types/semver,@types/sinon,aws-cdk-lib,axios,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fast-check,jest,jest-environment-node,jest-mock,license-checker,madge,nock,projen,sinon,ts-jest,ts-mock-imports,xml-js,@aws-cdk/cx-api,@aws-cdk/region-info,@aws-sdk/middleware-endpoint,@aws-sdk/util-retry,@aws-sdk/util-waiter,@smithy/middleware-endpoint,@smithy/property-provider,@smithy/shared-ini-file-loader,@smithy/types,@smithy/util-retry,@smithy/util-stream,@smithy/util-waiter,archiver,glob,minimatch,promptly,proxy-agent,semver,table,uuid" } ] }, diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 156e8470a..c5b024ce3 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -40,7 +40,7 @@ "@aws-cdk/user-input-gen": "^0.0.0", "@cdklabs/eslint-plugin": "^1.3.2", "@octokit/rest": "^21.1.1", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/archiver": "^6.0.3", "@types/fs-extra": "^9", "@types/jest": "^29.5.14", diff --git a/packages/aws-cdk/tsconfig.dev.json b/packages/aws-cdk/tsconfig.dev.json index b776637ea..aa0be9feb 100644 --- a/packages/aws-cdk/tsconfig.dev.json +++ b/packages/aws-cdk/tsconfig.dev.json @@ -8,9 +8,10 @@ "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,8 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, "skipLibCheck": true, "composite": true, "outDir": "lib" diff --git a/packages/aws-cdk/tsconfig.json b/packages/aws-cdk/tsconfig.json index 0143b2913..10289802c 100644 --- a/packages/aws-cdk/tsconfig.json +++ b/packages/aws-cdk/tsconfig.json @@ -10,9 +10,10 @@ "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,8 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, "skipLibCheck": true, "composite": true }, diff --git a/packages/cdk-assets/.projen/deps.json b/packages/cdk-assets/.projen/deps.json index 21c46a0e0..c6860b745 100644 --- a/packages/cdk-assets/.projen/deps.json +++ b/packages/cdk-assets/.projen/deps.json @@ -14,6 +14,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/cdk-assets/.projen/tasks.json b/packages/cdk-assets/.projen/tasks.json index ad7bea1e9..37195591d 100644 --- a/packages/cdk-assets/.projen/tasks.json +++ b/packages/cdk-assets/.projen/tasks.json @@ -53,7 +53,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@smithy/types,@smithy/util-stream,@stylistic/eslint-plugin,@types/archiver,@types/jest,@types/yargs,aws-sdk-client-mock,aws-sdk-client-mock-jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fs-extra,graceful-fs,jest,jszip,license-checker,projen,ts-jest,@aws-cdk/cx-api,@smithy/config-resolver,@smithy/node-config-provider,archiver,glob,yargs" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@smithy/types,@smithy/util-stream,@types/archiver,@types/jest,@types/yargs,aws-sdk-client-mock,aws-sdk-client-mock-jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,fs-extra,graceful-fs,jest,jszip,license-checker,projen,ts-jest,@aws-cdk/cx-api,@smithy/config-resolver,@smithy/node-config-provider,archiver,glob,yargs" } ] }, diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index acf2a117e..397c993e9 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -39,7 +39,7 @@ "@cdklabs/eslint-plugin": "^1.3.2", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/archiver": "^6.0.3", "@types/jest": "^29.5.14", "@types/mime": "^2", diff --git a/packages/cdk-assets/tsconfig.dev.json b/packages/cdk-assets/tsconfig.dev.json index 4f6200ca1..1ba62e8ab 100644 --- a/packages/cdk-assets/tsconfig.dev.json +++ b/packages/cdk-assets/tsconfig.dev.json @@ -26,6 +26,7 @@ "stripInternal": true, "target": "ES2020", "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/cdk-assets/tsconfig.json b/packages/cdk-assets/tsconfig.json index 3d6fce02c..af6bda986 100644 --- a/packages/cdk-assets/tsconfig.json +++ b/packages/cdk-assets/tsconfig.json @@ -26,6 +26,7 @@ "stripInternal": true, "target": "ES2020", "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/packages/cdk/.projen/deps.json b/packages/cdk/.projen/deps.json index b1e35e83e..a76a3f071 100644 --- a/packages/cdk/.projen/deps.json +++ b/packages/cdk/.projen/deps.json @@ -6,6 +6,7 @@ }, { "name": "@stylistic/eslint-plugin", + "version": "^3", "type": "build" }, { diff --git a/packages/cdk/.projen/tasks.json b/packages/cdk/.projen/tasks.json index 1f70c84d5..c16a9b012 100644 --- a/packages/cdk/.projen/tasks.json +++ b/packages/cdk/.projen/tasks.json @@ -52,7 +52,7 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@stylistic/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@cdklabs/eslint-plugin,@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-jest,eslint-plugin-jsdoc,eslint-plugin-prettier,jest,license-checker,projen,ts-jest" } ] }, diff --git a/packages/cdk/package.json b/packages/cdk/package.json index 7ae075ea1..76597a5d3 100644 --- a/packages/cdk/package.json +++ b/packages/cdk/package.json @@ -35,7 +35,7 @@ }, "devDependencies": { "@cdklabs/eslint-plugin": "^1.3.2", - "@stylistic/eslint-plugin": "^3.1.0", + "@stylistic/eslint-plugin": "^3", "@types/jest": "^29.5.14", "@types/node": "^16", "@typescript-eslint/eslint-plugin": "^8", diff --git a/packages/cdk/tsconfig.dev.json b/packages/cdk/tsconfig.dev.json index 613c7a675..9eb0f3669 100644 --- a/packages/cdk/tsconfig.dev.json +++ b/packages/cdk/tsconfig.dev.json @@ -3,14 +3,15 @@ "compilerOptions": { "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -23,7 +24,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true, "outDir": "lib" }, diff --git a/packages/cdk/tsconfig.json b/packages/cdk/tsconfig.json index 6d6ac0b49..840a614ff 100644 --- a/packages/cdk/tsconfig.json +++ b/packages/cdk/tsconfig.json @@ -5,14 +5,15 @@ "outDir": "lib", "alwaysStrict": true, "declaration": true, - "esModuleInterop": true, + "esModuleInterop": false, "experimentalDecorators": true, "inlineSourceMap": true, "inlineSources": true, "lib": [ - "es2019" + "es2020", + "dom" ], - "module": "CommonJS", + "module": "commonjs", "noEmitOnError": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, @@ -25,7 +26,9 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2020", + "incremental": true, + "skipLibCheck": true, "composite": true }, "include": [ diff --git a/tsconfig.dev.json b/tsconfig.dev.json index 74dc35834..21bbcca88 100644 --- a/tsconfig.dev.json +++ b/tsconfig.dev.json @@ -68,6 +68,9 @@ }, { "path": "packages/cdk" + }, + { + "path": "packages/@aws-cdk/integ-runner" } ] } diff --git a/tsconfig.json b/tsconfig.json index d04636fc1..0db5ddfab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -65,6 +65,9 @@ }, { "path": "packages/cdk" + }, + { + "path": "packages/@aws-cdk/integ-runner" } ] } diff --git a/yarn.lock b/yarn.lock index 9a4453d60..e33275884 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,17 +26,22 @@ resolved "https://registry.yarnpkg.com/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.225.tgz#948fc755c96f3f6bdd6684535d37cad0ccea41b6" integrity sha512-fMPfR7PwiwQZwAux9tQ5LRrFJJfl5Vp3kR8GMc+H/PA/wql9+w8mk5gs6SDpwBFpT7n3XkZ5H98Ns5+g7/WMIg== +"@aws-cdk/asset-awscli-v1@^2.2.227": + version "2.2.228" + resolved "https://registry.yarnpkg.com/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.228.tgz#3ec321b76e51818fedd9e7eb639278536a2bfa1c" + integrity sha512-ToZPI+dEz2BKj//kD2V8oXAvpeBFec5w6tXxIQh/U2iiMLcaUVZw4sxR820jF2GDArZY2D/alVkcSkId0J6rtA== + "@aws-cdk/asset-node-proxy-agent-v6@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz#6d3c7860354d4856a7e75375f2f0ecab313b4989" integrity sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A== -"@aws-cdk/aws-service-spec@^0.1.60": - version "0.1.60" - resolved "https://registry.yarnpkg.com/@aws-cdk/aws-service-spec/-/aws-service-spec-0.1.60.tgz#06038eea8c7f7304b2838abf519c78106a0f6877" - integrity sha512-jowfQo8F5i3ln1r0vB+bV3EeD35+dOIXmmvJ1FZ7qhcPiY4ftJ6zgrk94izKmu4hnza9edjxfXRiVej8rdhTkQ== +"@aws-cdk/aws-service-spec@^0.1.62": + version "0.1.62" + resolved "https://registry.yarnpkg.com/@aws-cdk/aws-service-spec/-/aws-service-spec-0.1.62.tgz#7cb5f186f9805206ac7718f75d4c537d7727dc0d" + integrity sha512-E6jCjAHagp0OfGfTfGae/kctceuzLyJ+DuWLrmh/dTGVobUVdtObFLCE5X5u7LK2xq0YI9RRsC9pEJtAmD9bmw== dependencies: - "@aws-cdk/service-spec-types" "^0.0.126" + "@aws-cdk/service-spec-types" "^0.0.128" "@cdklabs/tskb" "^0.0.3" "@aws-cdk/cloud-assembly-schema@^39.2.0": @@ -47,6 +52,14 @@ jsonschema "~1.4.1" semver "^7.7.1" +"@aws-cdk/cloud-assembly-schema@^40.7.0": + version "40.7.0" + resolved "https://registry.yarnpkg.com/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-40.7.0.tgz#1d53d55fc616477965338f0de98192ec3a3ed9bc" + integrity sha512-00wVKn9pOOGXbeNwA4E8FUFt0zIB4PmSO7PvIiDWgpaFX3G/sWyy0A3s6bg/n2Yvkghu8r4a8ckm+mAzkAYmfA== + dependencies: + jsonschema "~1.4.1" + semver "^7.7.1" + "@aws-cdk/cx-api@^2.181.1": version "2.181.1" resolved "https://registry.yarnpkg.com/@aws-cdk/cx-api/-/cx-api-2.181.1.tgz#3703f43eabf657dcbde171d2a18417982ccfd6d0" @@ -54,12 +67,17 @@ dependencies: semver "^7.6.3" -"@aws-cdk/integ-runner@^2.72.1": - version "2.72.1" - resolved "https://registry.yarnpkg.com/@aws-cdk/integ-runner/-/integ-runner-2.72.1.tgz#c0ef2968182205aa4616305d581ba9d9e8e0266d" - integrity sha512-K+PHvPRrhLbGC33vro5kDNdol5HW/ECORLesxjk5LMXQGDgHqEIIlYgtloVAswlaNSpjopTGrH+/BZYI7Oa8eQ== +"@aws-cdk/cx-api@^2.184.1": + version "2.184.1" + resolved "https://registry.yarnpkg.com/@aws-cdk/cx-api/-/cx-api-2.184.1.tgz#989421a735c4b782b51b8f2993c29d5eb55f012a" + integrity sha512-D2JbqzU5uEkol0LEglTb3cjdbS3o9jbUrEZfBSk7zNb6Kjzu06TgYajcL/ZwAxYKs7U1HenwRaXBofPYENReGg== dependencies: - aws-cdk "2.72.1" + semver "^7.7.1" + +"@aws-cdk/integ-tests-alpha@2.184.1-alpha.0": + version "2.184.1-alpha.0" + resolved "https://registry.yarnpkg.com/@aws-cdk/integ-tests-alpha/-/integ-tests-alpha-2.184.1-alpha.0.tgz#0719db2d294eac42de58f320238b3cd9a0e5b8fc" + integrity sha512-9ca8uxcP41USi2Y/ulGFR9iCLEAofq6h8VcSMpJHRvJb3mQtBJ+WYwXIn+uyMtDBIWX4pOyMk/6XZDuZVpwOsg== "@aws-cdk/region-info@^2.181.1": version "2.181.1" @@ -73,6 +91,13 @@ dependencies: "@cdklabs/tskb" "^0.0.3" +"@aws-cdk/service-spec-types@^0.0.128": + version "0.0.128" + resolved "https://registry.yarnpkg.com/@aws-cdk/service-spec-types/-/service-spec-types-0.0.128.tgz#7f84406311664e08523501885b4e28d0e8e34f26" + integrity sha512-wAYyf6xiYXObUR/f83iSd8cQ4TgDuk7h909wgmTMIIWxId1NJGw8o0TvInYjHP0GtXIFGoHoeO2efKsp72YbBw== + dependencies: + "@cdklabs/tskb" "^0.0.3" + "@aws-crypto/crc32@5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" @@ -1929,7 +1954,7 @@ gonzales-pe "^4.3.0" node-source-walk "^7.0.1" -"@emnapi/core@^1.1.0": +"@emnapi/core@^1.1.0", "@emnapi/core@^1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.3.1.tgz#9c62d185372d1bddc94682b87f376e03dfac3f16" integrity sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog== @@ -1937,7 +1962,7 @@ "@emnapi/wasi-threads" "1.0.1" tslib "^2.4.0" -"@emnapi/runtime@^1.1.0": +"@emnapi/runtime@^1.1.0", "@emnapi/runtime@^1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60" integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== @@ -2504,6 +2529,15 @@ "@emnapi/runtime" "^1.1.0" "@tybys/wasm-util" "^0.9.0" +"@napi-rs/wasm-runtime@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.7.tgz#288f03812a408bc53c2c3686c65f38fe90f295eb" + integrity sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw== + dependencies: + "@emnapi/core" "^1.3.1" + "@emnapi/runtime" "^1.3.1" + "@tybys/wasm-util" "^0.9.0" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -3374,7 +3408,7 @@ "@smithy/types" "^4.1.0" tslib "^2.6.2" -"@stylistic/eslint-plugin@^3.1.0": +"@stylistic/eslint-plugin@^3": version "3.1.0" resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-3.1.0.tgz#a9f655c518f76bfc5feb46b467d0f06e511b289d" integrity sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g== @@ -3702,6 +3736,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== +"@types/workerpool@^6": + version "6.4.7" + resolved "https://registry.yarnpkg.com/@types/workerpool/-/workerpool-6.4.7.tgz#f486a08d81fb785b3605da49f0552614c4866c23" + integrity sha512-DI2U4obcMzFViyNjLw0xXspim++qkAJ4BWRdYPVMMFtOpTvMr6PAk3UTZEoSqnZnvgUkJ3ck97Ybk+iIfuJHMg== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -3807,6 +3848,63 @@ "@typescript-eslint/types" "8.25.0" eslint-visitor-keys "^4.2.0" +"@unrs/rspack-resolver-binding-darwin-arm64@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-darwin-arm64/-/rspack-resolver-binding-darwin-arm64-1.2.1.tgz#ef76ae8ee116684ef84be7636dacbdfc53f27947" + integrity sha512-xgSjy64typsn/lhQk/uKaS363H7ZeIBlWSh25FJFWXSCeLMHpEZ0umDo5Vzqi5iS26OZ5R1SpQkwiS78GhQRjw== + +"@unrs/rspack-resolver-binding-darwin-x64@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-darwin-x64/-/rspack-resolver-binding-darwin-x64-1.2.1.tgz#691fabdf45ae8084f8daf84eb2d4bf4ac0a98b07" + integrity sha512-3maDtW0vehzciEbuLxc2g+0FmDw5LGfCt+yMN1ZDn0lW0ikEBEFp6ul3h2fRphtfuCc7IvBJE9WWTt1UHkS7Nw== + +"@unrs/rspack-resolver-binding-freebsd-x64@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-freebsd-x64/-/rspack-resolver-binding-freebsd-x64-1.2.1.tgz#ac80565aa59cbc3d2e469143976079b5b06644a7" + integrity sha512-aN6ifws9rNLjK2+6sIU9wvHyjXEf3S5+EZTHRarzd4jfa8i5pA7Mwt28un2DZVrBtIxhWDQvUPVKGI7zSBfVCA== + +"@unrs/rspack-resolver-binding-linux-arm-gnueabihf@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-linux-arm-gnueabihf/-/rspack-resolver-binding-linux-arm-gnueabihf-1.2.1.tgz#c5fce8cafe3eff7db1c859a02f7ee2a9213e6e94" + integrity sha512-tKqu9VQyCO1yEUX6n6jgOHi7SJA9e6lvHczK60gur4VBITxnPmVYiCj2aekrOOIavvvjjuWAL2rqPQuc4g7RHQ== + +"@unrs/rspack-resolver-binding-linux-arm64-gnu@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-linux-arm64-gnu/-/rspack-resolver-binding-linux-arm64-gnu-1.2.1.tgz#6cd04c044057791ce8eed60b1d8b7eacc8be0ec2" + integrity sha512-+xDI0kvwPiCR7334O83TPfaUXSe0UMVi5srQpQxP4+SDVYuONWsbwAC1IXe+yfOwRVGZsUdW9wE0ZiWs4Z+egw== + +"@unrs/rspack-resolver-binding-linux-arm64-musl@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-linux-arm64-musl/-/rspack-resolver-binding-linux-arm64-musl-1.2.1.tgz#46e55287e5022cbb56683da6b1075a9610ef76f6" + integrity sha512-fcrVHlw+6UgQliMbI0znFD4ASWKuyY17FdH67ZmyNH62b0hRhhxQuJE0D6N3410m8lKVu4QW4EzFiHxYFUC0cg== + +"@unrs/rspack-resolver-binding-linux-x64-gnu@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-linux-x64-gnu/-/rspack-resolver-binding-linux-x64-gnu-1.2.1.tgz#3064ca8e109b187e9d209760f943e400d10f2724" + integrity sha512-xISTyUJ2PiAT4x9nlh8FdciDcdKbsatgK9qO7EEsILt9VB7Y1mHYGaszj3ouxfZnaKQ13WwW+dFLGxkZLP/WVg== + +"@unrs/rspack-resolver-binding-linux-x64-musl@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-linux-x64-musl/-/rspack-resolver-binding-linux-x64-musl-1.2.1.tgz#1baee513e514fc8bdc0ba261d63f77a0821c74ff" + integrity sha512-LE8EjE/iPlvSsFbZ6P9c0Jh5/pifAi03UYeXYwOnQqt1molKAPMB0R4kGWOM7dnDYaNgkk1MN9MOTCLsqe97Fw== + +"@unrs/rspack-resolver-binding-wasm32-wasi@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-wasm32-wasi/-/rspack-resolver-binding-wasm32-wasi-1.2.1.tgz#3a31b8cd69e5ac1506924a598051fe2954b860d8" + integrity sha512-XERT3B88+G55RgG96May8QvAdgGzHr8qtQ70cIdbuWTpIcA0I76cnxSZ8Qwx33y73jE5N/myX2YKDlFksn4z6w== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.7" + +"@unrs/rspack-resolver-binding-win32-arm64-msvc@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-win32-arm64-msvc/-/rspack-resolver-binding-win32-arm64-msvc-1.2.1.tgz#0dad1f2dfc26903e28727dd7c0dcc3a171870d74" + integrity sha512-I8OLI6JbmNx2E/SG8MOEuo/d6rNx8dwgL09rcItSMcP82v1oZ8AY8HNA+axxuxEH95nkb6MPJU09p63isDvzrA== + +"@unrs/rspack-resolver-binding-win32-x64-msvc@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@unrs/rspack-resolver-binding-win32-x64-msvc/-/rspack-resolver-binding-win32-x64-msvc-1.2.1.tgz#6fcb04b7012edd4f8bd97641780012af1ec81c04" + integrity sha512-s5WvCljhFqiE3McvaD3lDIsQpmk7gEJRUHy1PRwLPzEB7snq9P2xQeqgzdjGhJQq62jBFz7NDy7NbMkocWr2pw== + "@vitest/expect@>1.6.0": version "3.0.7" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.0.7.tgz#3490936bc1e97fc21d53441518d51cb7116c698a" @@ -4250,12 +4348,25 @@ aws-cdk-lib@^2.181.1: table "^6.8.2" yaml "1.10.2" -aws-cdk@2.72.1: - version "2.72.1" - resolved "https://registry.yarnpkg.com/aws-cdk/-/aws-cdk-2.72.1.tgz#5c8dc41239ed7f47d2dd2f54afb980df2a58a24b" - integrity sha512-Noihlxyurq9ecz/aTx+j3raeedI0hcPaYFKqS1CkFDoOEvLHIuIEB6regoJHWy9GER/yYYgKu68c7xYo3LaZPA== - optionalDependencies: - fsevents "2.3.2" +aws-cdk-lib@^2.184.1: + version "2.184.1" + resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.184.1.tgz#0e66c9a82a1ac7dc25696520aaf4640f5198624c" + integrity sha512-No9g0SGadiDz0IEUIeJg4wSV/jFCGcouW2zUOTjV8OU4gTMoGiqC8BYSv7E6ucUtW6rmSFVK+pbc8XOFZOo1cg== + dependencies: + "@aws-cdk/asset-awscli-v1" "^2.2.227" + "@aws-cdk/asset-node-proxy-agent-v6" "^2.1.0" + "@aws-cdk/cloud-assembly-schema" "^40.7.0" + "@balena/dockerignore" "^1.0.2" + case "1.6.3" + fs-extra "^11.3.0" + ignore "^5.3.2" + jsonschema "^1.5.0" + mime-types "^2.1.35" + minimatch "^3.1.2" + punycode "^2.3.1" + semver "^7.7.1" + table "^6.9.0" + yaml "1.10.2" aws-sdk-client-mock-jest@^4.1.0: version "4.1.0" @@ -4821,7 +4932,7 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -constructs@^10.0.0: +constructs@^10, constructs@^10.0.0: version "10.4.2" resolved "https://registry.yarnpkg.com/constructs/-/constructs-10.4.2.tgz#e875a78bef932cca12ea63965969873a25c1c132" integrity sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA== @@ -5164,6 +5275,17 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-spawn@^6.0.0: + version "6.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57" + integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" @@ -5236,7 +5358,7 @@ dateformat@^3.0.0, dateformat@^3.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7, debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -5571,7 +5693,7 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -end-of-stream@^1.4.1: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -5782,6 +5904,11 @@ eslint-config-prettier@^10.0.2: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz#47444de8aa104ce82c2f91ad2a5e96b62c01e20d" integrity sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg== +eslint-config-prettier@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz#cf0ff6e5c4e7e15f129f1f1ce2a5ecba92dec132" + integrity sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw== + eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" @@ -5804,6 +5931,17 @@ eslint-import-resolver-typescript@^3.8.3: stable-hash "^0.0.4" tinyglobby "^0.2.12" +eslint-import-resolver-typescript@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.2.1.tgz#a48bbe43490dea494eed34c2bf5152249aba7d84" + integrity sha512-jAAKR08YRFtlRpxK3OnixV0JB88lH3Xo7HWn1KpKlEvtVUlLMAcRCcBvWT1KAnfT4jPAs4veyFxuUqSdg/Vd3g== + dependencies: + debug "^4.4.0" + get-tsconfig "^4.10.0" + rspack-resolver "^1.2.0" + stable-hash "^0.0.5" + tinyglobby "^0.2.12" + eslint-module-utils@^2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" @@ -5860,6 +5998,23 @@ eslint-plugin-jsdoc@^50.6.3: spdx-expression-parse "^4.0.0" synckit "^0.9.1" +eslint-plugin-jsdoc@^50.6.8: + version "50.6.8" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.8.tgz#c541c1eaaeb14e97c53397a8495ee60889943c62" + integrity sha512-PPZVqhoXaalMQwDGzcQrJtPSPIPOYsSMtvkjYAdsIazOW20yhYtVX4+jLL+XznD4zYTXyZbPWPRKkNev4D4lyw== + dependencies: + "@es-joy/jsdoccomment" "~0.49.0" + are-docs-informative "^0.0.2" + comment-parser "1.4.1" + debug "^4.3.6" + escape-string-regexp "^4.0.0" + espree "^10.1.0" + esquery "^1.6.0" + parse-imports "^2.1.1" + semver "^7.6.3" + spdx-expression-parse "^4.0.0" + synckit "^0.9.1" + eslint-plugin-prettier@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" @@ -5979,6 +6134,19 @@ events@3.3.0, events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -6271,11 +6439,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -6365,6 +6528,13 @@ get-proto@^1.0.0, get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -6967,6 +7137,11 @@ is-shared-array-buffer@^1.0.4: dependencies: call-bound "^1.0.3" +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + is-stream@^2.0.0, is-stream@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -7744,7 +7919,7 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsonschema@^1.4.1: +jsonschema@^1.4.1, jsonschema@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.5.0.tgz#f6aceb1ab9123563dd901d05f81f9d4883d3b7d8" integrity sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw== @@ -8166,7 +8341,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.8: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8, minimist@~1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -8246,6 +8421,11 @@ netmask@^2.0.2: resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + nise@^6.0.0, nise@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/nise/-/nise-6.1.1.tgz#78ea93cc49be122e44cb7c8fdf597b0e8778b64a" @@ -8326,6 +8506,13 @@ npm-normalize-package-bin@^1.0.0: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== + dependencies: + path-key "^2.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -8440,7 +8627,7 @@ object.values@^1.2.0: define-properties "^1.2.1" es-object-atoms "^1.0.0" -once@^1.3.0, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -8541,6 +8728,11 @@ own-keys@^1.0.1: object-keys "^1.1.1" safe-push-apply "^1.0.0" +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -8697,6 +8889,11 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -8889,6 +9086,26 @@ projen@^0.91.13: yaml "^2.2.2" yargs "^17.7.2" +projen@^0.91.18: + version "0.91.18" + resolved "https://registry.yarnpkg.com/projen/-/projen-0.91.18.tgz#b3f42ec06330475bce05d09d7a7840017fa21438" + integrity sha512-Hzvxc/lXRD9E6vcrNf6VrO/XmLshxa861d4A6t8RAAmSJ5/N+FDm7EvTQxZwGEiIZEqmQR2mttHaULdU3EWimg== + dependencies: + "@iarna/toml" "^2.2.5" + case "^1.6.3" + chalk "^4.1.2" + comment-json "4.2.2" + constructs "^10.0.0" + conventional-changelog-config-spec "^2.1.0" + fast-json-patch "^3.1.1" + glob "^8" + ini "^2.0.0" + semver "^7.7.1" + shx "^0.4.0" + xmlbuilder2 "^3.1.1" + yaml "^2.2.2" + yargs "^17.7.2" + promptly@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/promptly/-/promptly-3.2.0.tgz#a5517fbbf59bd31c1751d4e1d9bef1714f42b9d8" @@ -8928,6 +9145,14 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +pump@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode.js@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" @@ -9245,6 +9470,23 @@ rrweb-cssom@^0.8.0: resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz#3021d1b4352fbf3b614aaeed0bc0d5739abe0bc2" integrity sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw== +rspack-resolver@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rspack-resolver/-/rspack-resolver-1.2.1.tgz#158a87d58ce4eca9eda80f647ee21ca83703ffaf" + integrity sha512-yTaWGUvHOjcoyFMdVTdYt2nq2Hu8sw6ia3X9szloXFJlWLQZnQ9g/4TPhL3Bb3qN58Mkye8mFG7MCaKhya7fOw== + optionalDependencies: + "@unrs/rspack-resolver-binding-darwin-arm64" "1.2.1" + "@unrs/rspack-resolver-binding-darwin-x64" "1.2.1" + "@unrs/rspack-resolver-binding-freebsd-x64" "1.2.1" + "@unrs/rspack-resolver-binding-linux-arm-gnueabihf" "1.2.1" + "@unrs/rspack-resolver-binding-linux-arm64-gnu" "1.2.1" + "@unrs/rspack-resolver-binding-linux-arm64-musl" "1.2.1" + "@unrs/rspack-resolver-binding-linux-x64-gnu" "1.2.1" + "@unrs/rspack-resolver-binding-linux-x64-musl" "1.2.1" + "@unrs/rspack-resolver-binding-wasm32-wasi" "1.2.1" + "@unrs/rspack-resolver-binding-win32-arm64-msvc" "1.2.1" + "@unrs/rspack-resolver-binding-win32-x64-msvc" "1.2.1" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -9383,6 +9625,13 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -9390,6 +9639,11 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -9404,6 +9658,16 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +shelljs@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.9.2.tgz#a8ac724434520cd7ae24d52071e37a18ac2bb183" + integrity sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw== + dependencies: + execa "^1.0.0" + fast-glob "^3.3.2" + interpret "^1.0.0" + rechoir "^0.6.2" + shlex@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/shlex/-/shlex-2.1.2.tgz#5b5384d603885281c1dee05d56975865edddcba0" @@ -9417,6 +9681,14 @@ shx@^0.3.4: minimist "^1.2.3" shelljs "^0.8.5" +shx@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/shx/-/shx-0.4.0.tgz#c6ea6ace7e778da0ab32d2eab9def59d788e9336" + integrity sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA== + dependencies: + minimist "^1.2.8" + shelljs "^0.9.2" + side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" @@ -9457,7 +9729,7 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -9665,6 +9937,11 @@ stable-hash@^0.0.4: resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.4.tgz#55ae7dadc13e4b3faed13601587cec41859b42f7" integrity sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g== +stable-hash@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269" + integrity sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA== + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -9869,6 +10146,11 @@ strip-bom@^4.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== + strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -10520,6 +10802,13 @@ which-typed-array@^1.1.16, which-typed-array@^1.1.18: gopd "^1.2.0" has-tostringtag "^1.0.2" +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -10537,7 +10826,7 @@ wordwrap@>=0.0.2, wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -workerpool@^6.5.1: +workerpool@^6, workerpool@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== @@ -10703,7 +10992,7 @@ yargs@^15: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.0, yargs@^16.2.0: +yargs@^16, yargs@^16.0.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==