-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Describe the bug
After test file discovery integ-runner
changes the working directory from the users's cwd (usually the project root) to the test file's parent directory and then runs the cdk command, which (when using Python) means that the cwd and sys.path are in an unexpected state.
This means that we cannot import Stacks or Constructs from directories in the project which are above or adjacent to the test files. Since this is the expected location of Stacks and Constructs - that makes integ-runner
unusable in python.
Given a CDK project of file layout like the below:
my-cdk-app/
├─ my_cdk_app/
│ ├─ my_stack.py
│ ├─ lambda/
│ │ ├─ index.py
├─ test/
│ ├─ integ_.my_stack.py
├─ app.py
├─ cdk.json
While in app.py
it's expected that we would from my_cdk_app.my_stack import MyStack
, within inter_.my_stack.py
we are unable to do so.
Since the working directory has changed before we spawn the cdk and python subprocesses the sys.path
doesn't contain the root of the project and we get a ModuleNotFoundError
Secondly, if my_stack.py
contains a relative path definition, like for a Lambda function Code.from_asset(f"{os.get_cwd()} /my_cdk_app/lambda")
. Then the relative path would break as you're now working from a base path of /test
instead of the root path /
of the project. And, so the asset cannot be found at /test/my_cdk_app/lambda
since it's at /my_cdk_app/lambda
.
Expected Behavior
I expect the cdk
command and the integ-runner
commands to run in the same way - whereby the current working directory is the directory that I run the command from.
It's very common to expect that the cwd is the directory that the user initiates a script from. And the script is expected, by user, to be integ-runner
, not integ_.my_stack.py
.
Current Behavior
The integ-runner
command runs the cdk
command after changing directories. Therefore the cwd is inconsistent and unexpected and results in ModuleNotFoundErrors and missing assets for lambda, Dockerfiles, S3Deployments and other stacks which use a path to define the location of assets.
Reproduction Steps
Create a CDK project:
mkdir my_cdk_app
cd my_cdk_app
cdk init --language python
Add an integ-runner test:
mkdir test
touch test/integ_.my_cdk_app.py
And populate that test file with:
# test/integ_.my_cdk_app.py
import aws_cdk as cdk
from aws_cdk import (
integ_tests_alpha,
)
from my_cdk_app.my_cdk_app_stack import MyCdkAppStack
app = cdk.App()
stack = MyCdkAppStack(app, "TestStack")
integration_test = integ_tests_alpha.IntegTest(app, "Integ", test_cases=[stack])
synth = app.synth()
Then, when you run integ-runner
you will get the ModuleNotFoundError
:
Verifying integration test snapshots...
Traceback (most recent call last):
File "/workspaces/my_cdk_app/test/integ_.my_cdk_app.py", line 6, in <module>
from my_cdk_app.my_cdk_app_stack import MyCdkAppStack
ModuleNotFoundError: No module named 'my_cdk_app'
While cdk synth
will successfully import from my_cdk_app.my_cdk_app_stack import MyCdkAppStack
and synthesis the stack.
Possible Solution
To fix the behaviour in a hacky way, we can edit the test file, adding this to the top:
import sys
sys.path.insert(0, project_root_path)
Where project_root_path
is the absolute path within your developer machine to the project root - in my case "/workspaces/my_cdk_app"
.
After this, it will successfully run.
When I need to fix the cwd to make Code.from_asset
work as expected I need to also add:
import os
os.chdir(project_root_path)
This is very hacky, and as the project might live in different locations between different developers, it's very brittle.
So, I made https://pypi.org/project/cdk-integ-runner-cwd-fix/ to provide a less brittle, but still hacky fix.
Using that I need to add to the top of each test file:
from cdk_integ_runner_cwd_fix import fix_cwd
fix_cwd()
And then run inter-runner while providing the project root path as an environment variable:
CDK_INTEG_RUNNER_CWD=$(pwd) integ-runner
Doing so, shows no (so far) problems with the operation of integ-runner, so it would be much preferred if integ-runner
didn't introduce this unexpected change in working directory in the first place, and we didn't need to hack the path and CWD at all.
You could introduce a --cwd
option to integ-runner
which would incorporate a similar approach. Or, untangle all of the chdir that happens between test file discovery and test file being run.
Additional Information/Context
integ-runner --version
>>> 2.128.0-alpha.0
CDK CLI Version
2.122.0 (build 7e77e02)
Framework Version
No response
Node.js Version
v20.11.0
OS
debian bullseye
Language
Python
Language Version
Python 3.12.0
Other information
No response