-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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 non-TypeScript tests #22521
Conversation
…or the tests. This allows for tests written in other languages than TypeScript to be evaluated. Changed integration test file discovery to work with the naming conventions of all languages supported by CDK. Updated unit tests for integ-runner.
…was problematic and broke some existing tests (unit tests in TS named integration-tests.ts for example). Changed to use a different regex pattern to discover tests with different extensions.
Hey @karakter98 this is great! I've started similar work in #22058 but your PR looks much better. One note though that @corymhall and I have been discussing a slightly different interface:
Naming of these options aside, adding
|
Sorry for stepping over the existing draft PR, but the last activity on it was 23 days ago, so I just assumed it went stale and went ahead to open a new one |
This actually looks great to me, I did struggle a bit to test the Java version, so some default implementation would be a great UX improvement. I also like the idea of marking {filePath} in the --app flag, it allows for more complex commands. I assume that the custom match pattern falls back to some defaults per language, as in my current implementation? I believe it would be trivial to implement it. About the naming, I wanted to avoid having an --app parameter to not be confused with the CDK CLI --app parameter which had a little different structure, but if we introduce {filePath} the format is kind of the same: |
All good, you are 100% right about my PR becoming stale. :D This was mostly for reference, but it sounds like you did already come across it anyway. |
Yes, pretty much like what you did.
Tbh, we went back on forth on it. Like you we liked the similarity to CDK CLI. But |
What do you think about, instead of another |
I'm definitely open to this idea. What I'm not sure about is how this would work in practice. I imagine we would have to scan for all patterns and would then run tests for multiple languages all at once? Is that a good thing? How would it work with co-located JS/TS files, would these tests just run twice or would we give preference to one of them? |
It would allow for tests in different languages to run at the same time, since the app command is set per test in We could just say "if you need custom Regarding TS/JS interaction, if we have a test written in TS named If the TS and JS files had the same name, but different extensions, then the JS file would get overwritten at build time by the compiled TS version, but this is not something we can solve from our code, it's just the way the build process works. Since they need to have the same file name, it seems too narrow of an edge case. I think it's safe to do it, but if there are any concerns, we can just go the |
Yep, that makes a lot of sense.
I'm coming from the assumption that we need support for running TypeScript tests directly via On the other hand, we have projects where source TS files and compiled JS files are placed in the same directory ( So I'm really only concerned about TS projects that are compiled to JS and places in the same directory. This appears to be a quite common scenario to me.
I'd like to solve it, because I think you're right that auto-detection would be the much better UX. Either way we should have To me this now sounds like we have only one open question: What should the default value of
|
Let's go with
If we suppose that same filename (without extension) for We can actually go further, and filter out tests with the same name in general for any languages, because they would overwrite one another's snapshots anyway. In this case, the TS RegEx also should exclude If all sounds good, I'll get to work on this. |
I'm happy with this, thanks for the discussion & contribution! 🎉 While you're on the code, I can get to work and figure out the default RegEx and apps for each language. {
javascript: new IntegrationTestPreset('node {filePath}', [new RegExp(/^integ\..*\.js$/)]),
typescript: new IntegrationTestPreset('node -r ts-node/register {filePath}', [new RegExp(/^integ\.(?!.*\.d\.ts$).*\.ts$/)]),
python: new IntegrationTestPreset(`${pythonExecutable()} {filePath}`, [new RegExp(/^integ_.*\.py$/)]),
// these are guessed from the template app and still need some testing
go: new IntegrationTestPreset('go mod download && go run {filePath}', [new RegExp(/^integ_.*\.go$/)]),
csharp: new IntegrationTestPreset('dotnet run {filePath}', [new RegExp(/^Integ.*\.cs$/)]),
fsharp: new IntegrationTestPreset('dotnet run {filePath}', [new RegExp(/^Integ.*\.fs$/)]),
// No idea, yours will be good enough for now
java: new IntegrationTestPreset('tbd', [new RegExp(/^Integ.*\.java$/)]),
}; |
Now implements default run commands for all languages. Implemented different matching patterns for different file extensions. Now filters out duplicate test names, and makes sure to give precedence to .ts files over their compiled .js files. Java default Maven run command is now inferred from the directory structure of the Java project. The classpath for each individual test will automatically be discovered, together with the closest pom.xml file in the project hierarchy.
…mpiled file, but broke if run with ts-node directly.
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
@mrgrain I found a solution to get the Java files executed properly in Maven projects, and implemented the rest of the stuff we talked about, please let me know if there's anything else you would like to address in this PR. Thanks for the input! |
That's awesome! I'll review it tomorrow and double check the c/fsharp & go app strings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff @karakter98! I dropped a few minor suggestions in. The bigger issues we need to address tough are:
- Language Integration tests - Great work here so far. I'll need to check if/how we can handle them in our CI process. From what I can see we don't run them right now, which might be okay. I will also provide additional tests for the other languages.
- We should support configuring the new options via config file as well. See
fromFile
inpackages/@aws-cdk/integ-runner/lib/runner/integration-tests.ts
- Give .js preference over .ts (see inline comment)
- I've missed to explicitly state an additional functional requirement: Fully custom integration tests. With these changes, we would like the following to be possible:
integ-runner --app 'cat {filePath}' --test-regex 'integ-.*\.yaml'
(assumingcat {filePath}
would provide a valid cdk app)
Or in other words: support running integ tests with completely custom apps and unknown file types, as long as both--app
and--test-regex
are provided.
I think with the current approach this is not possible. I can see a couple of options here, but from a UX perspective I wonder if this would make sense:- if
--language
is provided we limit any automatics to the stored regular expressions for the selected language - if only
--app
is provided we don't use automatics to detect the app command. We still use the regular expressions for all listed languages to detect files.
Using--app
only makes sense if either--test-regex
is provided, or--language
is explicitly provided or the test directory only contains tests in one language. We could also enforce this. - if only
--test-regex
is provided, we use only the provided regex to match full filenames (not split in prefix/suffix)
We would still use the (language filtered) suffix list to auto-detect the app command for a given file.--test-regex
can now also be an array option
- if both
--app
and--test-regex
are provided we do not do any automatics. Effectively--language
is ignored.
- if
Let me know if you have any questions, especially re the fully custom integration tests feature. Apologies for not making this explicit earlier.
|
||
const language = new IntegrationTests(this.directory).getLanguage(parsed.base); | ||
if (!language) { | ||
throw new Error('Given file does not match any of the allowed languages for this test'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new Error('Given file does not match any of the allowed languages for this test'); | |
throw new Error(`Integration test '${parsed.base}' does not match any of the supported languages.'); |
const suffix = this.suffixMapping.get(language); | ||
const prefix = this.prefixMapping.get(language); | ||
|
||
return <boolean>(suffix?.test(fileName) && prefix?.test(fileName)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return <boolean>(suffix?.test(fileName) && prefix?.test(fileName)); | |
return Boolean(suffix?.test(fileName) && prefix?.test(fileName)); |
// Additionally, to give precedence to .ts files over their compiled .js version, | ||
// use descending lexicographic ordering, so the .ts files are picked up first. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've discussed this with the team and we now think that .js files should be given priority over .ts files.
In scenarios where TS is explicitly compiled to JS, it's usually preferred to run tests from the compiled version. Otherwise a user would have setup "on-the-fly" processes with ts-node and never produce compiled js files. This is also consistent with how ts-node
works if a .js
of the same file is present.
for (const integFileName of integs.sort().reverse()) { | ||
const testName = this.stripPrefixAndSuffix(path.basename(integFileName)); | ||
if (!discoveredTestNames.has(testName)) { | ||
integsWithoutDuplicates.push(integFileName); | ||
} | ||
discoveredTestNames.add(testName); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add print a logger.warning()
for every duplicate test that has been discarded.
@@ -1,2 +1,3 @@ | |||
export * from './api'; | |||
export { cli } from './cli'; | |||
export { pythonExecutable } from './init'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert (see note about pythonExecutable
)
export { pythonExecutable } from './init'; |
@@ -46,7 +46,7 @@ export async function cliInit(type?: string, language?: string, canUseNetwork = | |||
/** | |||
* Returns the name of the Python executable for this OS | |||
*/ | |||
function pythonExecutable() { | |||
export function pythonExecutable() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert (see note about pythonExecutable
)
export function pythonExecutable() { | |
function pythonExecutable() { |
@@ -1,6 +1,7 @@ | |||
import * as path from 'path'; | |||
import { TestCase, DefaultCdkOptions } from '@aws-cdk/cloud-assembly-schema'; | |||
import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS, TARGET_PARTITIONS, FUTURE_FLAGS_EXPIRED } from '@aws-cdk/cx-api'; | |||
import { pythonExecutable } from 'aws-cdk/lib/init'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for trying to avoid duplication! In this case we avoid importing from submodules and the functions is not something we'd like to be part of a public interface.
Let's keeps the duplication here for now.
import { pythonExecutable } from 'aws-cdk/lib/init'; |
* You can specify a custom run command, and it will be applied to all test files. | ||
* 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` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @default - test run command will be `node` | |
* @default - a default run command based on the language the test is written in |
.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 name should be inserted. Example: --app="python3.8 {filePath}"' }) | ||
.option('language', { type: 'array', default: ['csharp', 'fsharp', 'go', 'java', 'javascript', 'python', 'typescript'], desc: 'The languages that tests will search for. Defaults to all languages supported by CDK.' }) | ||
.option('test-regex', { type: 'string', default: undefined, desc: 'A custom pattern in the JS RegExp format to match integration test file prefixes.' }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.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 name should be inserted. Example: --app="python3.8 {filePath}"' }) | |
.option('language', { type: 'array', default: ['csharp', 'fsharp', 'go', 'java', 'javascript', 'python', 'typescript'], desc: 'The languages that tests will search for. Defaults to all languages supported by CDK.' }) | |
.option('test-regex', { type: 'string', default: undefined, desc: 'A custom pattern in the JS RegExp format to match integration test file prefixes.' }) | |
.option('app', { type: 'string', default: undefined, desc: 'The command used by the test runner to synth the test files. Uses default run commands based on the language the test is written in. You can use {filePath} in the command to specify where the test file name should be inserted in the command. Example: `--app "python3.8 {filePath}"`' }) | |
.option('language', { type: 'array', default: ['csharp', 'fsharp', 'go', 'java', 'javascript', 'python', 'typescript'], desc: 'The language to discover tests for. Defaults to all CDK-supported languages.' }) | |
.option('test-regex', { type: 'string', default: undefined, desc: 'A custom pattern in the JS RegExp format to match integration test file prefixes. Defaults are set based on naming conventions for the language the test is written in. Example: `--test-regex "^Integ\."`' }) |
…of multi-language integration tests (#22716) To support multi language integration tests better (see #22521), we need to rename the snapshot directories. Other languages have different naming conventions, so it's not trivial anymore to generate a "nice" name just from a test file. Instead we now use the full filename. This new pattern is inspired by Jest etc that all use the full filename. E.g. `my-test-name.integ.snapshot` -> `integ.my-test-name.js.snapshot` This PR changes the code generating the snapshot names and then does the rename in one go via the following commits: * chore: change code for generating the integ test snapshot directory names * chore: rename test data in `integ-runner` * chore: update `.gitignore` files with new snapshot patterns * chore: rename all integ-test snapshots * chore: update integ test snapshot paths in docs * chore: update `.npmignore` files with new snapshot pattern * chore: update prlinter to detect new snapshot pattern --- Review by commit ([start here](a884681)). The [middle commit](fee824d) contains most of the renames, is HUGE and takes a long time to load in the GitHub UI. However it only contains renames (use `--diff-filter=r` to exclude renames from the diff): ``` > git show --diff-filter=r fee824d (empty result) ``` ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] 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*
@karakter98 the snapshot rename has been merged. I'll start preparing |
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. |
1 similar comment
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. |
Yeah yeah 😹 |
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. |
3 similar comments
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. |
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. |
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. |
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. |
3 similar comments
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. |
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. |
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. |
To prepare for supporting other languages than TypeScript (see #22521) we need to be able to run test files with commands other than the current default `node`. With this PR, users can specify a custom `--app` command that will substitute the string `{filePath}` with the filename of each discovered test, and synth each test with that command. Example usage: `integ-runner --app '"node --no-warnings {filePath}"'` Until we also allow discovery of different file prefixes, this can't be used to run languages like Python, because the default prefix used now (`integ.`) contains a `.` which is not a valid character for Python module names. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] 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*
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. |
This PR has been in the MERGE CONFLICTS 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. |
… files (#22786) Follow-up to #22761. To support other languages than JavaScript (see #22521) we need to be able to detect test files with any patterns. With this PR, users can specify a number of custom `--test-regex` patterns that will bed used to discover integration test files. Together with `--app` this can already be used to run integ tests in arbitrary languages. Example usage: `integ-runner --app="python3 {filePath}" --test-regex="^integ_.*\.py$"` Also contains a minor refactor to make `--app` available via `IntegrationTests.fromFile()`. This is in preparation of an upcoming change to reestablish support for an integration test config file. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] 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*
@karakter98 #22786 got merged as well 🚀 Would you like to prepare the next PR with initial support for I'd probably suggest to start with |
@mrgrain sure, I'll open a PR for TS/JS later today |
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.
The pull request linter fails with the following errors:
PRs must pass status checks before we can provide a meaningful review. |
At the moment, the integ-tests library is only useful to TypeScript users of CDK, because integ-runner defaults to evaluating integration test files with node.
This PR adds a new parameter to the integ-runner CLI, to specify a different run command for the test files. The default run command is still node, to keep backwards compatibility.
Example usage:
integ-runner --test-run-command python3
Specifying the run command like this is needed because integration tests don't have a cdk.json file where their --app flag can be found (as mentioned in this thread).
Another important change is to the expected naming convention of integration tests. Up until now, all tests were expected to be prefixed with the "integ." prefix. This is fine for TypeScript/JavaScript, but other CDK languages have different naming conventions for source files:
To accommodate all of these different naming conventions, the test discovery logic was changed to use a RegEx that works with the following prefix patterns:
Also, another RegEx for valid file extensions was added (.js, .py, etc) to distinguish files generated by compiled languages (for example, TypeScript generates .js files, and the .js files should be tested, not the .ts ones). I am not sure about the valid extensions for C# and Java tests, so if someone with experience in those languages can take a look, it would be much appreciated.
I checked the changes locally with this command and an integration test written in Python:
integ-runner --directory test/test-data-python --update-on-failed --dry-run --test-run-command python3
And Java:
export $CLASSPATH="$(cd test/test-data-java; mvn dependency:build-classpath -q -Dmdep.outputFile=/dev/stdout)"; integ-runner --directory test/test-data-java/src/main/java/com/myorg --update-on-failed --dry-run --test-run-command="java -cp $CLASSPATH"
The Java command is a little awkward, but I couldn't find a way to pass mvn a file name, so I used the single-file source code feature from JDK 11 to test it. I assume there are better ways, but that's the best I could come up with.
I committed the generated snapshot and a unit test. I don't think integration tests are needed, since there are no changes to existing constructs.
Fixes #21169
All Submissions:
Adding new Unconventional Dependencies:
New Features
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