Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(integ-runner): support --language presets for TypeScript and JavaScript #22927

Closed
wants to merge 2 commits into from

Conversation

karakter98
Copy link
Contributor

Users can now run integration tests written in any CDK language since #22761 and #22786 added support for custom --app run commands and --test-regex to discover files with naming conventions specific to their language.

Since it's cumbersome and error-prone to always specify these flags when running the tests, this PR makes the first step to introduce language presets with default app run commands and test file regex discovery for each language.

This PR only introduces javascript and typescript presets, but it can easily be extended to all the other CDK-supported languages.

All supported language presets are enabled by default, but users can also specify a single language or a list of languages to use for running the tests (integ-runner --language javascript --language typescript).

See the discussion at #22521 for more background on this topic.

Shoutout to @mrgrain for the amazing collaboration and insights for this feature!


All Submissions:

Adding new Unconventional Dependencies:

  • This PR adds new unconventional dependencies following the process described here

New Features

  • Have you added the new feature to an integration test?
    • Did you use yarn integ to deploy the infrastructure and generate the snapshot (i.e. yarn integ without --dry-run)?

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Nov 15, 2022

@github-actions github-actions bot added beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK p2 labels Nov 15, 2022
@aws-cdk-automation aws-cdk-automation requested a review from a team November 15, 2022 23:18
@karakter98 karakter98 changed the title feat(integ-runner): support --language presets feat(integ-runner): support --language presets for TypeScript and JavaScript Nov 15, 2022
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: d2b89f6
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

@mrgrain mrgrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple minor (but blocking) changes.

But also a bigger refactoring idea, non-blocking. Let me know what you think. I don't want you to do unnecessary work if you feel it's not really worth it (I can always refactor this myself later)

@@ -41,4 +41,15 @@ describe('CLI', () => {
].join('\n'),
]]);
});

test('find only TypeScript files', async () => {
await main(['--list', '--language', 'typescript', '--directory=test/test-data-typescript', '--test-regex="^xxxxx\\..*(?<!\\.d)\\.ts$"']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await main(['--list', '--language', 'typescript', '--directory=test/test-data-typescript', '--test-regex="^xxxxx\\..*(?<!\\.d)\\.ts$"']);
await main(['--list', '--language', 'typescript', '--directory=test/test-data-typescript']);

Otherwise this is just testing the regex, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test won't be picked up if we don't specify the regex, because it doesn't have the standard prefix integ. but rather xxxxx.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see comment re renaming the test file.
#22927 (comment)

@@ -32,6 +32,7 @@ export async function main(args: string[]) {
.option('disable-update-workflow', { type: 'boolean', default: false, desc: 'If this is "true" then the stack update workflow will be disabled' })
.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: [] })
.option('language', { type: 'array', default: ['javascript', 'typescript'], desc: 'The language presets to run tests for. Only javascript and typescript are supported for now.' })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.option('language', { type: 'array', default: ['javascript', 'typescript'], desc: 'The language presets to run tests for. Only javascript and typescript are supported for now.' })
.option('language', { type: 'array', choices: ['javascript', 'typescript'], default: ['javascript', 'typescript'], desc: 'The language presets to run tests for.' })

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to check if adding defaultDescription: 'all supported languages' provides a better ux

@@ -0,0 +1,9 @@
import { App, Stack } from '@aws-cdk/core';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is okay to be named integ.typescript-test.ts

(The other ones aren't because they are empty files that only need to exist for mocking purposes and we should probably try to just get rid of them at some point)

Comment on lines +40 to +55
private static readonly defaultSuffixes = new Map<string, RegExp>([
['javascript', new RegExp(/\.js$/)],
// Allow files ending in .ts but not in .d.ts
['typescript', new RegExp(/(?<!\.d)\.ts$/)],
]);

private static readonly defaultAppCommands = new Map<string, string>([
['javascript', 'node {filePath}'],
['typescript', 'node -r ts-node/register {filePath}'],
]);

private static getLanguage(fileName: string): string | undefined {
const [language] = Array.from(IntegTest.defaultSuffixes.entries()).find(([, regex]) => regex.test(fileName)) ?? [undefined, undefined];
return language;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels out of place here. See comment further down for a possible refactoring.

Comment on lines +236 to +240
private static readonly defaultDiscoveryRegexes = new Map<string, RegExp>([
['javascript', new RegExp(/^integ\..*\.js$/)],
// Allow files ending in .ts but not in .d.ts
['typescript', new RegExp(/^integ\..*(?<!\.d)\.ts$/)],
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see why you had to split the regexes and app commands. But the split and duplication with language detection feels odd.

discoveredTestNames.add(testName);
}

return this.request(integsWithoutDuplicates, options);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the above changes, I think it's time to just merge request() into this function. Will make it bit easier.

Comment on lines +317 to +323
for (const integFileName of integs.sort()) {
const testName = path.parse(integFileName).name;
if (!discoveredTestNames.has(testName)) {
integsWithoutDuplicates.push(integFileName);
}
discoveredTestNames.add(testName);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if still need a generic de-duplication or just a special case if languages includes 'typescript' AND 'javascript'

Either way could we reduce duplication if we added the files to be ignored to options.exclude and let filterTests() do its work?

Comment on lines -251 to 309
const patterns = options.testRegex ?? ['^integ\\..*\\.js$'];
const languagePresets = options.language ?? Array.from(IntegrationTests.defaultDiscoveryRegexes.keys());
const patterns = options.testRegex?.map((pattern) => new RegExp(pattern))
?? Array.from(IntegrationTests.defaultDiscoveryRegexes.entries()).filter(
([language]) => languagePresets.includes(language),
).map(([_, regex]) => regex);

const files = await this.readTree();
const integs = files.filter(fileName => patterns.some((p) => {
const regex = new RegExp(p);
const integs = files.filter(fileName => patterns.some((regex) => {
return regex.test(fileName) || regex.test(path.basename(fileName));
}));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so here's an idea how we could streamline the language presets a bit. Instead of IntegrationTestsDiscoveryOptions having all three: testRegex app and language we introduce a new map:

{
  "app command": ["test regex"],
  // e.g.
  "node {filePath}": ['^integ\\..*\\.js$']
}

(In case of --app and/or --test-regex we just amend the map accordingly)

That way you could mostly keep the current code, but add an outer loop around it:

for (const [appCommand, patterns] of Object.entries(options.theNewMapThingy)) {
  // do the old thing here
  // but also map the matched files to IntegTests
  const integs = 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, // this is now the `appCommand` from `theNewMapThingy`
    })); 
}

What do you think?

This would probably mean we need to move the conversion from list of language presets and/or --app/--test-regex to somewhere and call it from cli.ts.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

17 similar comments
@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR has been in the CHANGES REQUESTED state for 3 weeks, and looks abandoned. To keep this PR from being closed, please continue work on it. If not, it will automatically be closed in a week.

@mrgrain mrgrain self-assigned this Dec 9, 2022
@aws-cdk-automation
Copy link
Collaborator

This PR has been deemed to be abandoned, and will be automatically closed. Please create a new PR for these changes if you think this decision has been made in error.

@aws-cdk-automation aws-cdk-automation added the closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. label Dec 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. p2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants