Skip to content

Commit 69c9776

Browse files
committed
Make it easier and faster to iterate on task-sdk-integration-tests
There were a few of things that made task-sdk-tests iteration a bit unobvious and slower. With this PR, we should be able to iterate over task-sdk-integration-tests WAY faster and get more contributors involved in contributing to those. * It was not clear that prerequisite of running the tests was building PROD image for Pyton 3.10. This is now clear in the documentation. * PROD images can be built in two different modes - from sources with --installation-method equal to . or from packages with the --installatio-method equal to "apache-airflow". This was not clearly communicated during build and it is now printed at output * It was not clear that when you build PROD images from sources, you should first compile ui assets, because otehrwise the assets are not added as part of the image. With this PR the `breeze prod-image build` command checks if the .vite manifest is present in the right `dist` folders and will error out, suggesting to run `breeze compile-ui-assets` before. * when building PROD images from sources, it is faster to rebuild the images with `uv` than with `pip`. the --use-uv parameter now defaults to False when building from packages and to True when building from sources. * There was an error in .dockerignore where generated dist files were not added to context when PROD image was built from sources. This resulted in "permission denied' when such PROD images were used to run tests. * The test compose had fallback of Airflow 3.0.3 which would be misleading if it happened. Now, AIRFLOW_IMAGE_NAME is mandatory * We are now mounting sources of Airflow to inside the image by default and skip it in CI. This mounting happens in local environment where PROD image is built usually from sources, and it is disabled in CI by using --skip-mounting-local-volumes flag. We also do not stop docker compose by default when runnig it locally in order to make fast iteration the default. * We pass host operating system when starting the compose, and we only change ownership on Linux - this is a long running operation on MacOS because mounted filesystem is slow, but it's also not needed on MacOS because the file system also maps ownershipt and files created by Airflow are created with local user id. * We pass local user id to containers to make sure that the files created on linux are created by the local user (logs and the like). * We are now detecting whether docker-compose is running and when we run with locally mounted sources, we reuse those running containers. When we don't mount local sources, we shut-down the compose before running to make sure we do not have sources mounted - and we close the compose by default when we do not mount local sources. * When sources are mounted we are only enabling DEV_MODE inside the containers so that components are hot-reloading (new feature added in apache#57741 last weeks. This way you do not have to restart anything when sources are changed and you can re-run the tests when docker compose is running. * The environment are passsed now via .env file so that you can easily reproduce docke compose command locally * The docker compose files are not copied any more, they are moved directly to the top of 'task-sdk-integraiton-tests' and used from there. * Additional diagnostics added to show what's going on. * Handling verbose option from breeze by adding more debugging informatio * Updated documentation about the tests * Small QOL immprovement - if expected dags are not yet parsed by dag file processor, when test starts, getting their status will return 404 "Not Found". In such case our tests implemented a short retry scheme with tenacity
1 parent 0534b90 commit 69c9776

22 files changed

+514
-203
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ airflow/www/node_modules
140140

141141
# But ensure UI dist files are included
142142
!airflow-core/src/airflow/ui/dist
143+
!airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui/dist
143144
!providers/fab/src/airflow/providers/fab/www/dist
144145
!providers/edge3/src/airflow/providers/edge3/plugins/www/dist
145146

.github/workflows/additional-prod-image-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ jobs:
190190
make-mnt-writeable-and-cleanup: true
191191
id: breeze
192192
- name: "Run Task SDK integration tests"
193-
run: breeze testing task-sdk-integration-tests
193+
run: breeze testing task-sdk-integration-tests --skip-mounting-local-volumes
194194

195195
test-e2e-integration-tests-basic:
196196
name: "Test e2e integration tests with PROD image"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,6 @@ _e2e_test_report.json
281281

282282
# UV cache
283283
.uv-cache/
284+
285+
# Allow logs in task-sdk-integration-tests
286+
!/task-sdk-integration-tests/logs/

contributing-docs/testing/task_sdk_integration_tests.rst

Lines changed: 99 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,50 @@ Why Task SDK Integration?
6868
Running Task SDK Integration Tests
6969
----------------------------------
7070

71-
There are multiple ways to run Task SDK Integration Tests depending based on your preferences.
71+
Prerequisite - build PROD image
72+
...............................
73+
74+
.. note::
75+
76+
The task-sdk integration tests are using locally build production images started in docker-compose by
77+
Pytest. This means that while the tests are running in the environment that you start it from (usually
78+
local development environment), you need to first build the images that you want to test against.
79+
80+
You also need to make sure that your assets are built first.
81+
.. code-block:: bash
82+
83+
# From the Airflow repository root
84+
breeze compile-ui-assets
85+
86+
Then, you should build the base image once before running the tests. You can do it using Breeze:
87+
88+
.. code-block:: bash
89+
90+
# From the Airflow repository root
91+
breeze prod-image build --python 3.10
92+
93+
This will build the ``ghcr.io/apache/airflow/main/prod/python3.10.latest`` image that will be used by
94+
default to run the tests. The ``breeze prod image build`` command by default - when run from sources of
95+
airflow - will use the local sources and build the image using ``uv`` to speed up the build process. Also when
96+
building from sources it will check if the assets are built and will error if they are not. However it will
97+
not check if the assets are up to date - so make sure to run the ``breeze compile-ui-assets`` command
98+
above if you have changed any UI sources and did not build your assets after that.
99+
100+
Note that you do not have to rebuild the image every time you run the tests and change Python sources - because
101+
the docker-compose setup we use in tests will automatically mount the local Python sources into the
102+
container, so you can iterate quickly without rebuilding the image. However, if you want to test changes
103+
that affect the image (like modifying dependencies, system packages, rebuilding UI etc.) you will need to
104+
rebuild the image with the same command as above.
105+
106+
After you build the image, there are several ways to run Task SDK Integration Tests,
107+
depending based on your preferences.
72108

73109
Using Breeze
74110
............
75111

76112
The simplest way to run Task SDK Integration Tests is using Breeze, which provides CI like
77-
reproducibility:
113+
reproducibility
114+
78115

79116
.. code-block:: bash
80117
@@ -87,36 +124,74 @@ reproducibility:
87124
# Run with custom Docker image
88125
DOCKER_IMAGE=my-custom-airflow-image:latest breeze testing task-sdk-integration-tests
89126
90-
Running in Your Current Virtual Environment
91-
...........................................
127+
Using uv
128+
........
92129

93-
Since you're already working in the Airflow repository, you can run Task SDK Integration Tests
94-
directly:
130+
Since you're already working in the Airflow repository, you can run Task SDK Integration Tests directly:
95131

96132
**Run Tests**
97133

98134
.. code-block:: bash
99135
100136
# Navigate to task-sdk-integration-tests directory and run tests
101-
cd task-sdk-integration-tests/
137+
cd task-sdk-integration-tests
102138
uv run pytest -s
103139
104140
# Run specific test file
105-
cd task-sdk-integration-tests/
141+
cd task-sdk-integration-tests
106142
uv run pytest tests/task_sdk_tests/test_task_sdk_health.py -s
107143
108-
# Keep containers running for debugging
109-
cd task-sdk-integration-tests/
110-
SKIP_DOCKER_COMPOSE_DELETION=1 uv run pytest -s
111-
112144
**Optional: Set Custom Docker Image**
113145

114146
.. code-block:: bash
115147
116148
# Use a different Airflow image for testing
117-
cd task-sdk-integration-tests/
149+
cd task-sdk-integration-tests
118150
DOCKER_IMAGE=my-custom-airflow:latest uv run pytest -s
119151
152+
By default when you run your tests locally, the Docker Compose deployment is kept between the sessions,
153+
your local sources are mounted into the containers and the Airflow services are restarted automatically
154+
(hot reloaded) when Python sources change.
155+
156+
This allows for quick iterations without rebuilding the image or restarting the containers.
157+
158+
Stopping docker-compose
159+
.......................
160+
161+
When you finish testing locally (or when you updated dependencies and rebuild your images),
162+
you likely want to stop the running containers. You can stop the the running containers by running:
163+
164+
.. code-block:: bash
165+
166+
# Stop and remove containers
167+
cd task-sdk-integration-tests
168+
docker-compose down -v
169+
170+
Docker compose will be automatically started again next time you run the tests.
171+
172+
Running tests in the way CI does it
173+
....................................
174+
175+
Our CI runs the tests in a clean environment every time without mounting local sources. This means that
176+
any changes you have locally will not be visible inside the containers. You can reproduce it locally by adding
177+
--skip-mounting-local-volumes to breeze command or by setting SKIP_MOUNTING_LOCAL_VOLUMES=1 in your
178+
environment when running tests locally. Before that however make sure that your PROD image is rebuilt
179+
using latest sources. When you disable mounting local volumes, the containers will be stopped by default
180+
when the tests end, you can disable that by setting SKIP_DOCKER_COMPOSE_DELETION=1 in your environment
181+
or passing --skip-docker-compose-deletion to breeze command.
182+
183+
.. code-block:: bash
184+
185+
# Keep containers running for debugging
186+
cd task-sdk-integration-tests
187+
SKIP_MOUNTING_LOCAL_VOLUMES=1 uv run pytest -s
188+
189+
or
190+
191+
.. code-block:: bash
192+
193+
# Using Breeze to keep containers running
194+
breeze testing task-sdk-integration-tests --skip-mounting-local-volumes
120195
121196
Debugging Failed Tests
122197
......................
@@ -127,33 +202,23 @@ and the Docker Compose deployment is shut down. To debug issues more effectively
127202
.. code-block:: bash
128203
129204
# Run with maximum verbosity
130-
cd task-sdk-integration-tests/
205+
cd task-sdk-integration-tests
131206
uv run pytest tests/task_sdk_tests/ -vvv -s --tb=long
132207
133-
# Keep containers running for inspection (local environment)
134-
cd task-sdk-integration-tests/
135-
SKIP_DOCKER_COMPOSE_DELETION=1 uv run pytest tests/task_sdk_tests/test_task_sdk_health.py::test_task_sdk_health
136-
137-
# Keep containers running for inspection (using Breeze)
138-
breeze testing task-sdk-integration-tests --skip-docker-compose-deletion
139-
140-
# Inspect container logs (when containers are still running)
141-
cd task-sdk-integration-tests/docker
142-
docker-compose logs airflow-apiserver
143-
docker-compose logs airflow-scheduler
144-
docker-compose logs postgres
208+
# Inspect container logs (when containers are still running - which is default)
209+
# The -f flag follows the logs in real-time so you can open several terminals to monitor different services
210+
cd task-sdk-integration-tests
211+
docker-compose logs -f airflow-apiserver
212+
docker-compose logs -f airflow-scheduler
213+
docker-compose logs -f postgres
145214
146215
# Access running containers for interactive debugging
147-
docker-compose exec airflow-apiserver bash
148-
149-
.. tip::
150-
**Container Cleanup Control**: By default, the Docker Compose deployment is deleted after tests
151-
complete to keep your system clean. To keep containers running for debugging:
216+
docker-compose exec -it airflow-apiserver bash
152217
153-
- **Local environment**: Export ``SKIP_DOCKER_COMPOSE_DELETION=1`` before running tests
154-
- **Breeze environment**: Use the ``--skip-docker-compose-deletion`` flag
218+
Every time you save airflow source code, the components running inside the container will be restarted
219+
automatically (hot reloaded). You can disable this behaviour by setting SKIP_MOUNTING_LOCAL_VOLUMES=1
220+
as described above (but then your sources will not be mounted).
155221

156-
Remember to manually clean up containers when done: ``cd task-sdk-integration-tests/docker && docker-compose down -v``
157222

158223
Testing Custom Airflow Images
159224
..............................

0 commit comments

Comments
 (0)