metadata-ingestion-modules/airflow-plugin/DOCKER_TEST_GUIDE.md
This guide explains how to run Airflow plugin tests in Docker with automatic volume mounts for source code and golden files.
The Docker test environment uses tox to manage all dependencies:
Three ways to run tests:
./run-tests.shThe wrapper script automatically handles volume mounts and permissions:
cd metadata-ingestion-modules/airflow-plugin
# Run all tests with Airflow 3.1 (default)
./run-tests.sh
# Run tests with Airflow 2.9
./run-tests.sh py311-airflow29
# Run specific test
./run-tests.sh py311-airflow31 -- tests/integration/test_plugin.py::test_v2_basic_dag -v
# Update golden files (automatically mounted!)
./run-tests.sh py311-airflow31 -- --update-golden-files
# Rebuild Docker image before running
REBUILD=true ./run-tests.sh
Benefits:
Docker Compose automatically mounts volumes and caches tox environments:
cd metadata-ingestion-modules/airflow-plugin
# Run all tests with Airflow 3.1 (default)
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test
# Run tests with Airflow 2.9
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test py311-airflow29
# Run specific test
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py::test_v2_basic_dag -v
# Update golden files (automatically mounted!)
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test py311-airflow31 -- --update-golden-files
# Build the image
docker-compose -f docker-compose.test.yml build
Benefits:
If you need full control or don't want the wrapper:
# Build from repository root
cd /path/to/datahub
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test -t airflow-plugin-test .
# Run all tests with Airflow 3.1 (default)
docker run --rm airflow-plugin-test
# Run tests with Airflow 2.9
docker run --rm airflow-plugin-test py311-airflow29
# Run specific test
docker run --rm airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py::test_v2_basic_dag -v
# Update golden files (manual volume mount)
docker run --rm \
-v $(pwd)/metadata-ingestion-modules/airflow-plugin:/app/metadata-ingestion-modules/airflow-plugin \
airflow-plugin-test py311-airflow31 -- --update-golden-files
# Must be run from repository root
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test -t airflow-plugin-test .
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test \
--build-arg PYTHON_VERSION=3.10 \
-t airflow-plugin-test:py310 .
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test \
--build-arg TOX_ENV=py311-airflow29 \
-t airflow-plugin-test:af29 .
From tox.ini:
py39-airflow27 - Python 3.9, Airflow 2.7py310-airflow27 - Python 3.10, Airflow 2.7py310-airflow28 - Python 3.10, Airflow 2.8py311-airflow29 - Python 3.11, Airflow 2.9py311-airflow210 - Python 3.11, Airflow 2.10py311-airflow31 - Python 3.11, Airflow 3.1 (default)# With default environment (py311-airflow31)
docker run airflow-plugin-test
# With specific environment
docker run airflow-plugin-test py311-airflow29
docker run airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py -v
docker run airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py::test_v2_snowflake_operator_airflow3 -v
docker run airflow-plugin-test py311-airflow31 -- -k "snowflake" -v
# Stop on first failure
docker run airflow-plugin-test py311-airflow31 -- -x
# Show local variables in tracebacks
docker run airflow-plugin-test py311-airflow31 -- -l
# Verbose output
docker run airflow-plugin-test py311-airflow31 -- -vv
# Show captured output
docker run airflow-plugin-test py311-airflow31 -- -s
Golden files are automatically mounted when using the wrapper script or docker-compose!
# Update all golden files
./run-tests.sh py311-airflow31 -- --update-golden-files
# Update golden files for specific test
./run-tests.sh py311-airflow31 -- tests/integration/test_plugin.py::test_v2_snowflake_operator_airflow3 --update-golden-files
That's it! Golden files are automatically written to your local filesystem.
# Update all golden files
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test py311-airflow31 -- --update-golden-files
# Update golden files for specific test
docker-compose -f docker-compose.test.yml run --rm airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py::test_v2_snowflake_operator_airflow3 --update-golden-files
If you're using raw Docker commands, you need to mount the golden files directory:
# From repository root
docker run --rm \
-v $(pwd)/metadata-ingestion-modules/airflow-plugin:/app/metadata-ingestion-modules/airflow-plugin \
airflow-plugin-test py311-airflow31 -- --update-golden-files
# Or just mount the goldens directory
docker run --rm \
-v $(pwd)/metadata-ingestion-modules/airflow-plugin/tests/integration/goldens:/app/metadata-ingestion-modules/airflow-plugin/tests/integration/goldens \
airflow-plugin-test py311-airflow31 -- --update-golden-files
docker run -it --entrypoint /bin/bash airflow-plugin-test
# Inside container:
cd metadata-ingestion-modules/airflow-plugin
tox -e py311-airflow31 -- -v
docker run --entrypoint tox airflow-plugin-test -e py311-airflow29 -- tests/integration/ -v
Mount your local code for live editing:
docker run -v $(pwd):/app airflow-plugin-test py311-airflow31 -- tests/integration/ -v
Note: You may need to rebuild the tox environment after code changes:
docker run -v $(pwd):/app airflow-plugin-test py311-airflow31 --recreate
# Set different default at runtime
docker run -e TOX_ENV=py311-airflow29 airflow-plugin-test
docker run airflow-plugin-test py310-airflow27
docker run airflow-plugin-test py311-airflow29
docker run airflow-plugin-test py311-airflow31
The Dockerfile must be run from the repository root because it needs access to metadata-ingestion:
# ✅ Correct
cd /path/to/datahub
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test -t airflow-plugin-test .
# ❌ Wrong (will fail - can't find ../../metadata-ingestion)
cd /path/to/datahub/metadata-ingestion-modules/airflow-plugin
docker build -f Dockerfile.test -t airflow-plugin-test .
If you encounter stale dependencies:
# Rebuild tox environment
docker run airflow-plugin-test py311-airflow31 --recreate
# Or rebuild Docker image with no cache
docker build --no-cache -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test -t airflow-plugin-test .
Ensure the Python version in the Docker build matches the tox environment:
# For py310-* environments
docker build --build-arg PYTHON_VERSION=3.10 \
-f metadata-ingestion-modules/airflow-plugin/Dockerfile.test \
-t airflow-plugin-test:py310 .
docker run airflow-plugin-test:py310 py310-airflow28
When using volume mounts:
# Run with current user's UID/GID
docker run --user $(id -u):$(id -g) \
-v $(pwd)/metadata-ingestion-modules/airflow-plugin/tests/integration/goldens:/app/metadata-ingestion-modules/airflow-plugin/tests/integration/goldens \
airflow-plugin-test py311-airflow31 -- --update-golden-files
Tox may use significant memory when building environments:
docker run --memory=4g airflow-plugin-test
name: Test Airflow Plugin
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
tox-env:
- py310-airflow27
- py310-airflow28
- py311-airflow29
- py311-airflow210
- py311-airflow31
steps:
- uses: actions/checkout@v3
- name: Build test image
run: |
docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test \
-t airflow-plugin-test .
- name: Run tests
run: docker run airflow-plugin-test ${{ matrix.tox-env }}
test:
image: docker:latest
services:
- docker:dind
script:
- docker build -f metadata-ingestion-modules/airflow-plugin/Dockerfile.test -t airflow-plugin-test .
- docker run airflow-plugin-test $TOX_ENV
parallel:
matrix:
- TOX_ENV:
- py310-airflow27
- py310-airflow28
- py311-airflow29
- py311-airflow31
The tox.ini file defines all test environments with:
The entrypoint script intelligently routes commands:
# No args → run default tox environment
docker run airflow-plugin-test
# Executes: tox -e $TOX_ENV
# Tox env specified → run that environment
docker run airflow-plugin-test py311-airflow29
# Executes: tox -e py311-airflow29
# Other args → pass to pytest via default environment
docker run airflow-plugin-test -- -k snowflake -v
# Executes: tox -e $TOX_ENV -- -k snowflake -v
# Tox env + pytest args
docker run airflow-plugin-test py311-airflow31 -- tests/integration/test_plugin.py -v
# Executes: tox -e py311-airflow31 -- tests/integration/test_plugin.py -v
| Aspect | Docker | Local Tox |
|---|---|---|
| Setup | Build once, run anywhere | Requires local Python setup |
| Reproducibility | Guaranteed (same OS, packages) | Varies by local environment |
| CI/CD | Native support | Needs Python pre-installed |
| Speed (first run) | Slower (Docker build) | Slower (tox setup) |
| Speed (subsequent) | Fast if cached | Fast if cached |
| Disk Usage | Higher (Docker layers) | Lower |
| Isolation | Complete (OS level) | Python environment only |
| Golden Files | Volume mounts needed | Direct access |
Use Docker for:
Use Local Tox for:
metadata-ingestiondocker image pruneFor issues:
tox.ini in the airflow-plugin directorydocker logs <container-id>docker build --progress=plaindocker run -it --entrypoint /bin/bash airflow-plugin-test