Skip to content

Commit d430b2e

Browse files
authored
feat(integ-tests): add integ tests for the toolkit library (#430)
Add integration tests for the toolkit library. Introduces the toolkit library as a new "component under test". Because we want to promote writing integ tests against the toolkit library the same way we would write normal production code, the setup is like this: - The toolkit lib is installed as a `devDependency` into the integ test package. This will allow writing tests as if the toolkit lib is "just" a dependency. - At runtime, a version of the toolkit library can be selected and it will be installed into the dependency closure by the runner before the tests are run, so that the imports will still function properly. To signal this, we'll mark `@aws-cdk/toolkit-lib` as an `optionalDependency` as well. (PR includes #444) --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license Signed-off-by: github-actions <[email protected]>
1 parent 0f917d6 commit d430b2e

File tree

22 files changed

+296
-28
lines changed

22 files changed

+296
-28
lines changed

.github/workflows/integ.yml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projenrc.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,7 @@ const cliInteg = configureProject(
15731573
],
15741574
devDeps: [
15751575
yarnCling,
1576+
toolkitLib,
15761577
'@types/semver@^7',
15771578
'@types/yargs@^16',
15781579
'@types/fs-extra@^9',
@@ -1614,6 +1615,8 @@ const cliInteg = configureProject(
16141615
);
16151616
cliInteg.eslint?.addIgnorePattern('resources/**/*.ts');
16161617

1618+
cliInteg.deps.addDependency('@aws-cdk/toolkit-lib', pj.DependencyType.OPTIONAL);
1619+
16171620
const compiledDirs = ['tests', 'test', 'lib'];
16181621
for (const compiledDir of compiledDirs) {
16191622
cliInteg.gitignore.addPatterns(`${compiledDir}/**/*.js`);

packages/@aws-cdk-testing/cli-integ/.projen/deps.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/cli-integ/.projen/tasks.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/cli-integ/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ inject these dependencies into tests. Users can specify component versions, but
4545
Test Authors are responsible for taking these parameters and using it to set up
4646
the right environment for the tests.
4747

48-
| Component | Command-line argument | Default | Treatment by runner | Treatment in test |
49-
|-----------------------|--------------------------------------|-------------|----------------------------|-------------------------------------------|
50-
| CDK Construct Library | `--framework-version=VERSION` | Latest | Nothing | `npm install` into temporary project dir. |
51-
| CDK CLI | `--cli-version=VERSION` | Auto source | `npm install` into tempdir | Add to `$PATH`. |
48+
| Component | Command-line argument | Default | Treatment by runner | Treatment in test |
49+
|-----------------------|--------------------------------------|-------------|----------------------------|-----------------------------------------------|
50+
| CDK Construct Library | `--framework-version=VERSION` | Latest | Nothing | `npm install` into temporary project dir. |
51+
| CDK CLI | `--cli-version=VERSION` | Auto source | `npm install` into tempdir | Add to `$PATH`. |
5252
| | `--cli-source=ROOT` or `auto` | Auto source | | Add `<ROOT>/packages/aws-cdk/bin` to `$PATH`. |
53+
| Toolkit Library | `--toolkit-lib-version=VERSION` | Devdep | Install into its own deps | Nothing
5354

5455
### Running a test suite
5556

packages/@aws-cdk-testing/cli-integ/lib/cli/run-suite.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import * as yargs from 'yargs';
55
import { RunnerCliNpmSource } from '../package-sources/cli-npm-source';
66
import { RunnerCliRepoSource } from '../package-sources/cli-repo-source';
77
import { autoFindRepoRoot } from '../package-sources/find-root';
8+
import { RunnerLibraryGlobalInstallSource } from '../package-sources/library-globalinstall-source';
89
import { RunnerLibraryNpmSource } from '../package-sources/library-npm-source';
10+
import { RunnerLibraryPreinstalledSource } from '../package-sources/library-preinstalled-source';
911
import type { IRunnerSource, ITestCliSource, ITestLibrarySource } from '../package-sources/source';
1012
import { serializeSources } from '../package-sources/subprocess';
1113

@@ -34,6 +36,11 @@ async function main() {
3436
alias: 'f',
3537
type: 'string',
3638
})
39+
.options('toolkit-lib-version', {
40+
describe: 'Toolkit lib version to use',
41+
alias: 'l',
42+
type: 'string',
43+
})
3744
.option('use-source', {
3845
descripton: 'Use TypeScript packages from the given source repository (or "auto")',
3946
type: 'string',
@@ -117,11 +124,23 @@ async function main() {
117124
const librarySource: IRunnerSource<ITestLibrarySource>
118125
= new RunnerLibraryNpmSource('aws-cdk-lib', args['framework-version'] ? args['framework-version'] : 'latest');
119126

127+
const toolkitLibPackage = '@aws-cdk/toolkit-lib';
128+
let toolkitSource: IRunnerSource<ITestLibrarySource> | undefined;
129+
if (args['toolkit-lib-version']) {
130+
toolkitSource = new RunnerLibraryGlobalInstallSource(toolkitLibPackage, args['toolkit-lib-version']);
131+
}
132+
if (!toolkitSource) {
133+
toolkitSource = await RunnerLibraryPreinstalledSource.isPreinstalled(toolkitLibPackage)
134+
? new RunnerLibraryPreinstalledSource(toolkitLibPackage)
135+
: new RunnerLibraryGlobalInstallSource(toolkitLibPackage, 'latest');
136+
}
137+
120138
console.log('------> Configuration');
121-
console.log(` Test suite: ${suiteName}`);
122-
console.log(` Test version: ${thisPackageVersion()}`);
123-
console.log(` CLI source: ${cliSource.assert().sourceDescription}`);
124-
console.log(` Library source: ${librarySource.sourceDescription}`);
139+
console.log(` Test suite: ${suiteName}`);
140+
console.log(` Test version: ${thisPackageVersion()}`);
141+
console.log(` CLI source: ${cliSource.assert().sourceDescription}`);
142+
console.log(` Library source: ${librarySource.sourceDescription}`);
143+
console.log(` Toolkit lib source: ${toolkitSource.sourceDescription}`);
125144

126145
if (args.verbose) {
127146
process.env.VERBOSE = '1';
@@ -142,17 +161,24 @@ async function main() {
142161
console.log('------> Resolved versions');
143162
const cli = await cliSource.assert().runnerPrepare();
144163
disposables.push(cli);
145-
console.log(` CLI: ${cli.version}`);
164+
console.log(` CLI: ${cli.version}`);
146165

147166
const library = await librarySource.runnerPrepare();
148167
disposables.push(library);
149-
console.log(` Library: ${library.version}`);
168+
console.log(` Library: ${library.version}`);
169+
170+
const toolkitLib = await toolkitSource.runnerPrepare();
171+
disposables.push(toolkitLib);
172+
console.log(` Toolkit library: ${toolkitLib.version}`);
150173

151174
serializeSources({
152175
cli,
153176
library,
177+
toolkitLib,
154178
});
155179

180+
const jestConfig = path.resolve(__dirname, '..', '..', 'resources', 'integ.jest.config.js');
181+
156182
await jest.run([
157183
'--randomize',
158184
...args.runInBand ? ['-i'] : [],
@@ -161,7 +187,7 @@ async function main() {
161187
...args.maxWorkers ? [`--maxWorkers=${args.maxWorkers}`] : [],
162188
...passWithNoTests ? ['--passWithNoTests'] : [],
163189
...args['test-file'] ? [args['test-file']] : [],
164-
], path.resolve(__dirname, '..', '..', 'resources', 'integ.jest.config.js'));
190+
], jestConfig);
165191
} finally {
166192
for (const disp of disposables) {
167193
await disp.dispose();

packages/@aws-cdk-testing/cli-integ/lib/npm.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ export async function npmMostRecentMatching(packageName: string, range: string)
2424
return output[output.length - 1];
2525
}
2626

27+
export async function npmQueryInstalledVersion(packageName: string, dir: string) {
28+
const reportStr = await shell(['node', require.resolve('npm'), 'list', '--json', '--depth', '0', packageName], {
29+
cwd: dir,
30+
show: 'error',
31+
});
32+
const report = JSON.parse(reportStr);
33+
return report.dependencies[packageName].version;
34+
}
35+
2736
/**
2837
* Use NPM preinstalled on the machine to look up a list of TypeScript versions
2938
*/

packages/@aws-cdk-testing/cli-integ/lib/package-sources/cli-npm-source.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as os from 'os';
22
import * as path from 'path';
33
import * as fs from 'fs-extra';
44
import type { IRunnerSource, ITestCliSource, IPreparedRunnerSource } from './source';
5+
import { npmQueryInstalledVersion } from '../npm';
56
import { addToShellPath, rimraf, shell } from '../shell';
67

78
export class RunnerCliNpmSource implements IRunnerSource<ITestCliSource> {
@@ -18,13 +19,7 @@ export class RunnerCliNpmSource implements IRunnerSource<ITestCliSource> {
1819
await shell(['node', require.resolve('npm'), 'install', `aws-cdk@${this.range}`], {
1920
cwd: tempDir,
2021
});
21-
22-
const reportStr = await shell(['node', require.resolve('npm'), 'list', '--json', '--depth', '0', 'aws-cdk'], {
23-
cwd: tempDir,
24-
show: 'error',
25-
});
26-
const report = JSON.parse(reportStr);
27-
const installedVersion = report.dependencies['aws-cdk'].version;
22+
const installedVersion = await npmQueryInstalledVersion('aws-cdk', tempDir);
2823

2924
return {
3025
version: installedVersion,

packages/@aws-cdk-testing/cli-integ/lib/package-sources/cli-repo-source.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,25 @@ import { addToShellPath } from '../shell';
1010
*/
1111
export class RunnerCliRepoSource implements IRunnerSource<ITestCliSource> {
1212
public readonly sourceDescription: string;
13-
private readonly cliPath: string;
13+
private readonly cliBinPath: string;
1414

1515
constructor(private readonly repoRoot: string) {
16-
this.cliPath = path.join(this.repoRoot, 'packages', 'aws-cdk', 'bin');
17-
this.sourceDescription = this.cliPath;
16+
this.cliBinPath = path.join(this.repoRoot, 'packages', 'aws-cdk', 'bin');
17+
this.sourceDescription = this.cliBinPath;
1818
}
1919

2020
public async runnerPrepare(): Promise<IPreparedRunnerSource<ITestCliSource>> {
2121
if (!await fs.pathExists(path.join(this.repoRoot, 'package.json')) || !await fs.pathExists(path.join(this.repoRoot, 'yarn.lock'))) {
2222
throw new Error(`${this.repoRoot}: does not look like the repository root`);
2323
}
2424

25+
const pj = JSON.parse(await fs.readFile(path.join(this.cliBinPath, '..', 'package.json'), 'utf-8'));
26+
2527
return {
26-
version: '*',
28+
version: pj.version,
2729
dispose: () => Promise.resolve(),
2830
serialize: () => {
29-
return [TestCliRepoSource, [this.cliPath]];
31+
return [TestCliRepoSource, [this.cliBinPath]];
3032
},
3133
};
3234
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { promises as fs } from 'fs';
2+
import * as os from 'os';
3+
import * as path from 'path';
4+
import type { IRunnerSource, IPreparedRunnerSource, ITestLibrarySource } from './source';
5+
import { copyDirectoryContents } from '../files';
6+
import { npmQueryInstalledVersion } from '../npm';
7+
import { shell } from '../shell';
8+
9+
/**
10+
* A library dependency that cli-integ installs into its own `node_modules`.
11+
*/
12+
export class RunnerLibraryGlobalInstallSource implements IRunnerSource<ITestLibrarySource> {
13+
public readonly sourceDescription: string;
14+
15+
constructor(private readonly packageName: string, private readonly range: string) {
16+
this.sourceDescription = `${this.packageName}@${this.range}`;
17+
}
18+
19+
public async runnerPrepare(): Promise<IPreparedRunnerSource<ITestLibrarySource>> {
20+
// Create a tempdir where we install the requested package, then symlink into our `node_modules`
21+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'tmpcdk'));
22+
await fs.mkdir(tempDir, { recursive: true });
23+
24+
await shell(['node', require.resolve('npm'), 'install', `${this.packageName}@${this.range}`], {
25+
cwd: tempDir,
26+
});
27+
28+
const symlinkPath = path.join(__dirname, '..', '..', 'node_modules', this.packageName);
29+
await fs.mkdir(path.dirname(symlinkPath), { recursive: true });
30+
await fs.symlink(path.join(tempDir, 'node_modules', this.packageName), symlinkPath, 'junction');
31+
32+
const version = await npmQueryInstalledVersion(this.packageName, tempDir);
33+
34+
return {
35+
version,
36+
async dispose() {
37+
// Remove the symlink again
38+
await fs.rm(symlinkPath);
39+
},
40+
serialize: () => {
41+
return [TestLibraryGlobalInstallSource, [this.packageName, version]];
42+
},
43+
};
44+
}
45+
}
46+
47+
export class TestLibraryGlobalInstallSource implements ITestLibrarySource {
48+
constructor(public readonly packageName: string, private readonly version: string) {
49+
}
50+
51+
public requestedVersion(): string {
52+
return this.version;
53+
}
54+
55+
public assertJsiiPackagesAvailable(): void {
56+
// FIXME: Always a no-op.
57+
}
58+
59+
public async initializeDotnetPackages(currentDir: string): Promise<void> {
60+
// FIXME: this code has nothing to do with the package source, really, so shouldn't be here.
61+
if (process.env.CWD_FILES_DIR) {
62+
await copyDirectoryContents(process.env.CWD_FILES_DIR, currentDir);
63+
}
64+
}
65+
66+
public requestedAlphaVersion(): string {
67+
return this.version;
68+
}
69+
}
70+

0 commit comments

Comments
 (0)