diff --git a/packages/aws-cdk/CONTRIBUTING.md b/packages/aws-cdk/CONTRIBUTING.md
index 8df338dad6049..3d1190e4a1609 100644
--- a/packages/aws-cdk/CONTRIBUTING.md
+++ b/packages/aws-cdk/CONTRIBUTING.md
@@ -152,7 +152,7 @@ Following are the steps involved in running these tests:
- Download the previous version tarball from npm and extract the integration tests.
- Export a `FRAMWORK_VERSION` env variable based on the caller, and execute the integration tests of the previous version.
-7. Our integration tests now run and have knowledge of which framework version they should [install](./test/integ/cli/cdk-helpers.ts#L74).
+7. Our integration tests now run and have knowledge of which framework version they should [install](./test/integ/helpers/cdk.ts#L74).
That "basically" it, hope it makes sense...
diff --git a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts
index c7d1a7efbe171..c7cbb1fa862a9 100644
--- a/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts
+++ b/packages/aws-cdk/test/integ/cli/bootstrapping.integtest.ts
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
-import { randomString, withDefaultFixture } from './cdk-helpers';
-import { integTest } from './test-helpers';
+import { randomString, withDefaultFixture } from '../helpers/cdk';
+import { integTest } from '../helpers/test-helpers';
jest.setTimeout(600_000);
@@ -242,4 +242,4 @@ integTest('add tags, left alone on re-bootstrap', withDefaultFixture(async (fixt
expect(response.Stacks?.[0].Tags).toEqual([
{ Key: 'Foo', Value: 'Bar' },
]);
-}));
\ No newline at end of file
+}));
diff --git a/packages/aws-cdk/test/integ/cli/cli.integtest.ts b/packages/aws-cdk/test/integ/cli/cli.integtest.ts
index 407c1d7fd99c4..087efd00eb524 100644
--- a/packages/aws-cdk/test/integ/cli/cli.integtest.ts
+++ b/packages/aws-cdk/test/integ/cli/cli.integtest.ts
@@ -1,9 +1,9 @@
import { promises as fs } from 'fs';
import * as os from 'os';
import * as path from 'path';
-import { retry, sleep } from './aws-helpers';
-import { cloneDirectory, shell, withDefaultFixture } from './cdk-helpers';
-import { integTest } from './test-helpers';
+import { retry, sleep } from '../helpers/aws';
+import { cloneDirectory, shell, withDefaultFixture } from '../helpers/cdk';
+import { integTest } from '../helpers/test-helpers';
jest.setTimeout(600 * 1000);
diff --git a/packages/aws-cdk/test/integ/cli/test.sh b/packages/aws-cdk/test/integ/cli/test.sh
index 05be97e5312c3..bf0ec0a7c5c68 100755
--- a/packages/aws-cdk/test/integ/cli/test.sh
+++ b/packages/aws-cdk/test/integ/cli/test.sh
@@ -8,16 +8,5 @@ echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
cd $scriptdir
-# Install these dependencies that the tests (written in Jest) need.
-# Only if we're not running from the repo, because if we are the
-# dependencies have already been installed by the containing 'aws-cdk' package's
-# package.json.
-if ! npx --no-install jest --version; then
- echo 'Looks like we need to install jest first. Hold on.' >& 2
- npm install --prefix . jest jest-junit aws-sdk
-fi
-
-# This must --runInBand because parallelism is arranged for inside the tests
-# themselves and they must run in the same process in order to coordinate to
-# make sure no 2 tests use the same region at the same time.
-npx jest --runInBand --verbose "$@"
+source ../common/jest-test.bash
+invokeJest "$@"
diff --git a/packages/aws-cdk/test/integ/common/jest-test.bash b/packages/aws-cdk/test/integ/common/jest-test.bash
new file mode 100755
index 0000000000000..efec199933b1d
--- /dev/null
+++ b/packages/aws-cdk/test/integ/common/jest-test.bash
@@ -0,0 +1,15 @@
+function invokeJest() {
+ # Install these dependencies that the tests (written in Jest) need.
+ # Only if we're not running from the repo, because if we are the
+ # dependencies have already been installed by the containing 'aws-cdk' package's
+ # package.json.
+ if ! npx --no-install jest --version; then
+ echo 'Looks like we need to install jest first. Hold on.' >& 2
+ npm install --prefix . jest jest-junit aws-sdk
+ fi
+
+ # This must --runInBand because parallelism is arranged for inside the tests
+ # themselves and they must run in the same process in order to coordinate to
+ # make sure no 2 tests use the same region at the same time.
+ npx jest --runInBand --verbose "$@"
+}
diff --git a/packages/aws-cdk/test/integ/cli/aws-helpers.ts b/packages/aws-cdk/test/integ/helpers/aws.ts
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/aws-helpers.ts
rename to packages/aws-cdk/test/integ/helpers/aws.ts
diff --git a/packages/aws-cdk/test/integ/cli/cdk-helpers.ts b/packages/aws-cdk/test/integ/helpers/cdk.ts
similarity index 87%
rename from packages/aws-cdk/test/integ/cli/cdk-helpers.ts
rename to packages/aws-cdk/test/integ/helpers/cdk.ts
index f57ce2aee018a..81a656c83e023 100644
--- a/packages/aws-cdk/test/integ/cli/cdk-helpers.ts
+++ b/packages/aws-cdk/test/integ/helpers/cdk.ts
@@ -2,7 +2,7 @@ import * as child_process from 'child_process';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
-import { outputFromStack, AwsClients } from './aws-helpers';
+import { outputFromStack, AwsClients } from './aws';
import { ResourcePool } from './resource-pool';
import { TestContext } from './test-helpers';
@@ -52,7 +52,7 @@ export function withCdkApp(block: (context:
context.output.write(` Test directory: ${integTestDir}\n`);
context.output.write(` Region: ${context.aws.region}\n`);
- await cloneDirectory(path.join(__dirname, 'app'), integTestDir, context.output);
+ await cloneDirectory(path.join(__dirname, '..', 'cli', 'app'), integTestDir, context.output);
const fixture = new TestFixture(
integTestDir,
stackNamePrefix,
@@ -92,6 +92,51 @@ export function withCdkApp(block: (context:
};
}
+export function withMonolithicCfnIncludeCdkApp(block: (context: TestFixture) => Promise) {
+ return async (context: A) => {
+ const uberPackage = process.env.UBERPACKAGE;
+ if (!uberPackage) {
+ throw new Error('The UBERPACKAGE environment variable is required for running this test!');
+ }
+
+ const randy = randomString();
+ const stackNamePrefix = `cdk-uber-cfn-include-${randy}`;
+ const integTestDir = path.join(os.tmpdir(), `cdk-uber-cfn-include-${randy}`);
+
+ context.output.write(` Stack prefix: ${stackNamePrefix}\n`);
+ context.output.write(` Test directory: ${integTestDir}\n`);
+
+ const awsClients = await AwsClients.default(context.output);
+ await cloneDirectory(path.join(__dirname, '..', 'uberpackage', 'cfn-include-app'), integTestDir, context.output);
+ const fixture = new TestFixture(
+ integTestDir,
+ stackNamePrefix,
+ context.output,
+ awsClients,
+ );
+
+ let success = true;
+ try {
+ let module = uberPackage;
+ if (FRAMEWORK_VERSION) {
+ module = `${module}@${FRAMEWORK_VERSION}`;
+ }
+ await fixture.shell(['npm', 'install', 'constructs', module]);
+
+ await block(fixture);
+ } catch (e) {
+ success = false;
+ throw e;
+ } finally {
+ if (process.env.INTEG_NO_CLEAN) {
+ process.stderr.write(`Left test directory in '${integTestDir}' ($INTEG_NO_CLEAN)\n`);
+ } else {
+ await fixture.dispose(success);
+ }
+ }
+ };
+}
+
/**
* Default test fixture for most (all?) integ tests
*
@@ -370,10 +415,11 @@ export async function shell(command: string[], options: ShellOptions = {}): Prom
child.once('error', reject);
child.once('close', code => {
+ const output = (Buffer.concat(stdout).toString('utf-8') + Buffer.concat(stderr).toString('utf-8')).trim();
if (code === 0 || options.allowErrExit) {
- resolve((Buffer.concat(stdout).toString('utf-8') + Buffer.concat(stderr).toString('utf-8')).trim());
+ resolve(output);
} else {
- reject(new Error(`'${command.join(' ')}' exited with error code ${code}`));
+ reject(new Error(`'${command.join(' ')}' exited with error code ${code}. Output: \n${output}`));
}
});
});
diff --git a/packages/aws-cdk/test/integ/cli/corking.ts b/packages/aws-cdk/test/integ/helpers/corking.ts
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/corking.ts
rename to packages/aws-cdk/test/integ/helpers/corking.ts
diff --git a/packages/aws-cdk/test/integ/cli/resource-pool.test.ts b/packages/aws-cdk/test/integ/helpers/resource-pool.test.ts
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/resource-pool.test.ts
rename to packages/aws-cdk/test/integ/helpers/resource-pool.test.ts
diff --git a/packages/aws-cdk/test/integ/cli/resource-pool.ts b/packages/aws-cdk/test/integ/helpers/resource-pool.ts
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/resource-pool.ts
rename to packages/aws-cdk/test/integ/helpers/resource-pool.ts
diff --git a/packages/aws-cdk/test/integ/cli/skip-tests.txt b/packages/aws-cdk/test/integ/helpers/skip-tests.txt
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/skip-tests.txt
rename to packages/aws-cdk/test/integ/helpers/skip-tests.txt
diff --git a/packages/aws-cdk/test/integ/cli/test-helpers.ts b/packages/aws-cdk/test/integ/helpers/test-helpers.ts
similarity index 100%
rename from packages/aws-cdk/test/integ/cli/test-helpers.ts
rename to packages/aws-cdk/test/integ/helpers/test-helpers.ts
diff --git a/packages/aws-cdk/test/integ/run-against-dist.bash b/packages/aws-cdk/test/integ/run-against-dist.bash
index 83c29e82a5620..d3d349b9302f3 100644
--- a/packages/aws-cdk/test/integ/run-against-dist.bash
+++ b/packages/aws-cdk/test/integ/run-against-dist.bash
@@ -4,6 +4,8 @@ npmws=/tmp/cdk-rundist
rm -rf $npmws
mkdir -p $npmws
+set -x
+
# This script must create 1 or 2 traps, and the 'trap' command will replace
# the previous trap, so get some 'dynamic traps' mechanism in place
TRAPS=()
@@ -137,4 +139,4 @@ function prepare_python_packages() {
function pip() {
pip_ "$@"
-}
\ No newline at end of file
+}
diff --git a/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/.gitignore b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/.gitignore
new file mode 100644
index 0000000000000..71d72642a58e3
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/.gitignore
@@ -0,0 +1 @@
+!cfn-include-app.js
diff --git a/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cdk.json b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cdk.json
new file mode 100644
index 0000000000000..e5077eaaefe36
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cdk.json
@@ -0,0 +1,4 @@
+{
+ "app": "node cfn-include-app.js",
+ "versionReporting": false
+}
diff --git a/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cfn-include-app.js b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cfn-include-app.js
new file mode 100644
index 0000000000000..6c5ddc776bb59
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/cfn-include-app.js
@@ -0,0 +1,21 @@
+const path = require('path');
+
+const uberPackage = process.env.UBERPACKAGE;
+if (!uberPackage) {
+ throw new Error('The UBERPACKAGE environment variable is required for running this app!');
+}
+
+const cfn_inc = require(`${uberPackage}/cloudformation-include`);
+const core = require(`${uberPackage}`);
+
+const app = new core.App();
+const stack = new core.Stack(app, 'Stack');
+const cfnInclude = new cfn_inc.CfnInclude(stack, 'Template', {
+ templateFile: path.join(__dirname, 'example-template.json'),
+});
+const cfnBucket = cfnInclude.getResource('Bucket');
+if (cfnBucket.bucketName !== 'my-example-bucket') {
+ throw new Error(`Expected bucketName to be 'my-example-bucket', got: '${cfnBucket.bucketName}'`);
+}
+
+app.synth();
diff --git a/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/example-template.json b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/example-template.json
new file mode 100644
index 0000000000000..0385b58961413
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/cfn-include-app/example-template.json
@@ -0,0 +1,10 @@
+{
+ "Resources": {
+ "Bucket": {
+ "Type": "AWS::S3::Bucket",
+ "Properties": {
+ "BucketName": "my-example-bucket"
+ }
+ }
+ }
+}
diff --git a/packages/aws-cdk/test/integ/uberpackage/jest.config.js b/packages/aws-cdk/test/integ/uberpackage/jest.config.js
new file mode 100644
index 0000000000000..1e3fe3d13f96b
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/jest.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ moduleFileExtensions: [
+ "js",
+ ],
+ testMatch: [
+ "**/*.integtest.js",
+ ],
+ testEnvironment: "node",
+ bail: 1,
+ verbose: true,
+ reporters: [
+ "default",
+ [ "jest-junit", { suiteName: "jest tests", outputDirectory: "coverage" } ]
+ ]
+};
diff --git a/packages/aws-cdk/test/integ/uberpackage/test.sh b/packages/aws-cdk/test/integ/uberpackage/test.sh
new file mode 100755
index 0000000000000..41761b349580e
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/test.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -euo pipefail
+
+scriptdir=$(cd $(dirname $0) && pwd)
+
+echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
+echo 'UberCDK Integration Tests'
+echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
+
+cd $scriptdir
+
+source ../common/jest-test.bash
+invokeJest "$@"
diff --git a/packages/aws-cdk/test/integ/uberpackage/uberpackage.integtest.ts b/packages/aws-cdk/test/integ/uberpackage/uberpackage.integtest.ts
new file mode 100644
index 0000000000000..6521e4c8113a0
--- /dev/null
+++ b/packages/aws-cdk/test/integ/uberpackage/uberpackage.integtest.ts
@@ -0,0 +1,12 @@
+import { withMonolithicCfnIncludeCdkApp } from '../helpers/cdk';
+import { integTest } from '../helpers/test-helpers';
+
+jest.setTimeout(600_000);
+
+describe('uberpackage', () => {
+ integTest('works with cloudformation-include', withMonolithicCfnIncludeCdkApp(async (fixture) => {
+ fixture.log('Starting test of cfn-include with monolithic CDK');
+
+ await fixture.cdkSynth();
+ }));
+});
diff --git a/packages/aws-cdk/test/util/stack-monitor.test.ts b/packages/aws-cdk/test/util/stack-monitor.test.ts
index 289b14d5d7b41..7e2644b481b9f 100644
--- a/packages/aws-cdk/test/util/stack-monitor.test.ts
+++ b/packages/aws-cdk/test/util/stack-monitor.test.ts
@@ -1,5 +1,5 @@
import { StackActivityMonitor, IActivityPrinter, StackActivity } from '../../lib/api/util/cloudformation/stack-activity-monitor';
-import { sleep } from '../integ/cli/aws-helpers';
+import { sleep } from '../integ/helpers/aws';
import { MockSdk } from './mock-sdk';
let sdk: MockSdk;
@@ -167,4 +167,4 @@ async function waitForCondition(cb: () => boolean): Promise {
while (!cb()) {
await sleep(10);
}
-}
\ No newline at end of file
+}
diff --git a/tools/ubergen/bin/ubergen.ts b/tools/ubergen/bin/ubergen.ts
index a85a64ce7f2b9..5169dfcf814de 100644
--- a/tools/ubergen/bin/ubergen.ts
+++ b/tools/ubergen/bin/ubergen.ts
@@ -209,7 +209,7 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag
const indexStatements = new Array();
for (const library of libraries) {
const libDir = path.join(LIB_ROOT, library.shortName);
- await transformPackage(library, packageJson.jsii.targets, libDir, libraries);
+ await transformPackage(library, packageJson, libDir, libraries);
if (library.shortName === 'core') {
indexStatements.push(`export * from './${library.shortName}';`);
@@ -225,13 +225,13 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag
async function transformPackage(
library: LibraryReference,
- config: PackageJson['jsii']['targets'],
+ uberPackageJson: PackageJson,
destination: string,
allLibraries: readonly LibraryReference[],
) {
await fs.mkdirp(destination);
- await copyOrTransformFiles(library.root, destination, allLibraries);
+ await copyOrTransformFiles(library.root, destination, allLibraries, uberPackageJson);
await fs.writeFile(
path.join(destination, 'index.ts'),
@@ -240,6 +240,7 @@ async function transformPackage(
);
if (library.shortName !== 'core') {
+ const config = uberPackageJson.jsii.targets;
await fs.writeJson(
path.join(destination, '.jsiirc.json'),
{
@@ -291,7 +292,7 @@ function transformTargets(monoConfig: PackageJson['jsii']['targets'], targets: P
return result;
}
-async function copyOrTransformFiles(from: string, to: string, libraries: readonly LibraryReference[]) {
+async function copyOrTransformFiles(from: string, to: string, libraries: readonly LibraryReference[], uberPackageJson: PackageJson) {
const promises = (await fs.readdir(from)).map(async name => {
if (shouldIgnoreFile(name)) { return; }
@@ -308,7 +309,7 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl
const stat = await fs.stat(source);
if (stat.isDirectory()) {
await fs.mkdirp(destination);
- return copyOrTransformFiles(source, destination, libraries);
+ return copyOrTransformFiles(source, destination, libraries, uberPackageJson);
}
if (name.endsWith('.ts')) {
return fs.writeFile(
@@ -316,6 +317,17 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl
await rewriteImports(source, to, libraries),
{ encoding: 'utf8' },
);
+ } else if (name === 'cfn-types-2-classes.json') {
+ // This is a special file used by the cloudformation-include module that contains mappings
+ // of CFN resource types to the fully-qualified class names of the CDK L1 classes.
+ // We need to rewrite it to refer to the uberpackage instead of the individual packages
+ const cfnTypes2Classes: { [key: string]: string } = await fs.readJson(source);
+ for (const cfnType of Object.keys(cfnTypes2Classes)) {
+ const fqn = cfnTypes2Classes[cfnType];
+ // replace @aws-cdk/aws- with /aws-
+ cfnTypes2Classes[cfnType] = fqn.replace('@aws-cdk', uberPackageJson.name);
+ }
+ await fs.writeJson(destination, cfnTypes2Classes, { spaces: 2 });
} else {
return fs.copyFile(source, destination);
}