pytest-docker-compose-v2 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.github/workflows/release.yaml +3 -3
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.github/workflows/test.yaml +5 -3
- pytest_docker_compose_v2-0.3.0/Justfile +76 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/PKG-INFO +92 -4
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/README.md +89 -1
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/pyproject.toml +7 -4
- pytest_docker_compose_v2-0.3.0/pytest_docker_compose/__init__.py +1 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/pytest_docker_compose/plugin.py +44 -32
- pytest_docker_compose_v2-0.3.0/tests/pytest_docker_compose_tests/my_network/a_buildable_container/requirements.txt +3 -0
- pytest_docker_compose_v2-0.3.0/tests/pytest_docker_compose_tests/my_network/docker-compose.yml +33 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/test_function_scoping_fixtures.py +0 -1
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/test_module_scoping_fixtures.py +0 -1
- pytest_docker_compose_v2-0.3.0/tests/pytest_docker_compose_tests/test_wait_for_healthcheck.py +48 -0
- pytest_docker_compose_v2-0.3.0/uv.lock +1261 -0
- pytest_docker_compose_v2-0.2.0/pytest_docker_compose/__init__.py +0 -1
- pytest_docker_compose_v2-0.2.0/tests/pytest_docker_compose_tests/my_network/a_buildable_container/requirements.txt +0 -3
- pytest_docker_compose_v2-0.2.0/tests/pytest_docker_compose_tests/my_network/docker-compose.yml +0 -16
- pytest_docker_compose_v2-0.2.0/uv.lock +0 -976
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.devcontainer/Dockerfile +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.devcontainer/devcontainer.json +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.gitignore +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/LICENSE +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/my_network/a_buildable_container/Dockerfile +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/my_network/a_buildable_container/an_api.py +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/my_network/extra-service.yml +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/test_multiple_compose_files.py +0 -0
- {pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/tests/pytest_docker_compose_tests/test_wrong_scoping.py +0 -0
{pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.github/workflows/release.yaml
RENAMED
|
@@ -16,9 +16,9 @@ jobs:
|
|
|
16
16
|
id-token: write
|
|
17
17
|
steps:
|
|
18
18
|
- name: Check out repository
|
|
19
|
-
uses: actions/checkout@
|
|
19
|
+
uses: actions/checkout@v7
|
|
20
20
|
- name: Set up uv
|
|
21
|
-
uses: astral-sh/setup-uv@
|
|
21
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
22
22
|
with:
|
|
23
23
|
enable-cache: true
|
|
24
24
|
python-version: '3.13'
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
- name: Run tests
|
|
29
29
|
run: uv run pytest
|
|
30
30
|
- name: Create GitHub release
|
|
31
|
-
uses: softprops/action-gh-release@
|
|
31
|
+
uses: softprops/action-gh-release@v3
|
|
32
32
|
with:
|
|
33
33
|
name: Release ${{ github.ref }}
|
|
34
34
|
tag_name: ${{ github.ref }}
|
{pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/.github/workflows/test.yaml
RENAMED
|
@@ -18,14 +18,14 @@ jobs:
|
|
|
18
18
|
pytest-version: ['7', '8', '9']
|
|
19
19
|
steps:
|
|
20
20
|
- name: Check out repository
|
|
21
|
-
uses: actions/checkout@
|
|
21
|
+
uses: actions/checkout@v7
|
|
22
22
|
# needed because we use git describe to get a bumpver compatible GITHASH containing version
|
|
23
23
|
# alternatively can look at using HEXHASH instead. Note that these are purposefully not
|
|
24
24
|
# documented in the bumpver project, see issues/PRs for more info.
|
|
25
25
|
# with:
|
|
26
26
|
# fetch-depth: 0
|
|
27
27
|
- name: Set up uv
|
|
28
|
-
uses: astral-sh/setup-uv@
|
|
28
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
29
29
|
with:
|
|
30
30
|
enable-cache: true
|
|
31
31
|
python-version: ${{ matrix.python-version }}
|
|
@@ -34,7 +34,9 @@ jobs:
|
|
|
34
34
|
- name: Install pytest ${{ matrix.pytest-version }}
|
|
35
35
|
run: uv pip install "pytest>=${{ matrix.pytest-version }},<$(( ${{ matrix.pytest-version }} + 1 ))"
|
|
36
36
|
- name: Run tests
|
|
37
|
-
run: uv run pytest
|
|
37
|
+
run: uv run --no-sync pytest
|
|
38
|
+
- name: Run healthcheck wait tests
|
|
39
|
+
run: uv run --no-sync pytest -m wait_for_healthcheck --docker-compose ./tests/pytest_docker_compose_tests/my_network --docker-compose-wait
|
|
38
40
|
# NOTE: publishing to test repository is disabled until I figure out a way to do it reliably
|
|
39
41
|
# this means that we need to avoid version clashes as well as local versions
|
|
40
42
|
# see: https://github.com/pypa/packaging.python.org/issues/804
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
set shell := ["bash", "-euo", "pipefail", "-c"]
|
|
2
|
+
|
|
3
|
+
# Generate Markdown release notes for VERSION without modifying the repository.
|
|
4
|
+
release-notes version:
|
|
5
|
+
#!/usr/bin/env bash
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
version="{{ version }}"
|
|
9
|
+
if git show-ref --verify --quiet "refs/tags/${version}"; then
|
|
10
|
+
revision="${version}"
|
|
11
|
+
previous="$(git describe --tags --abbrev=0 "${version}^")"
|
|
12
|
+
else
|
|
13
|
+
revision="HEAD"
|
|
14
|
+
previous="$(git describe --tags --abbrev=0 HEAD)"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
uv run git-cliff "${previous}..${revision}" \
|
|
18
|
+
--tag "${version}" \
|
|
19
|
+
--config keepachangelog \
|
|
20
|
+
--strip all
|
|
21
|
+
|
|
22
|
+
# Add generated notes to an existing GitHub release (requires the GitHub CLI).
|
|
23
|
+
publish-release-notes version:
|
|
24
|
+
#!/usr/bin/env bash
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
command -v gh >/dev/null || {
|
|
28
|
+
echo "The GitHub CLI (gh) is required to publish release notes." >&2
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
notes_file="$(mktemp)"
|
|
33
|
+
trap 'rm -f "${notes_file}"' EXIT
|
|
34
|
+
uv run just release-notes "{{ version }}" > "${notes_file}"
|
|
35
|
+
gh release edit "{{ version }}" --notes-file "${notes_file}"
|
|
36
|
+
|
|
37
|
+
# Bump VERSION_KIND (patch, minor, or major), commit, tag, and push the release.
|
|
38
|
+
release version_kind:
|
|
39
|
+
#!/usr/bin/env bash
|
|
40
|
+
set -euo pipefail
|
|
41
|
+
|
|
42
|
+
version_kind="{{ version_kind }}"
|
|
43
|
+
case "${version_kind}" in
|
|
44
|
+
patch|minor|major) ;;
|
|
45
|
+
*)
|
|
46
|
+
echo "Version kind must be one of: patch, minor, major." >&2
|
|
47
|
+
exit 2
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
|
|
51
|
+
if [[ "$(git branch --show-current)" != "main" ]]; then
|
|
52
|
+
echo "Releases must be created from the main branch." >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
if [[ -n "$(git status --porcelain)" ]]; then
|
|
56
|
+
echo "The working tree must be clean before creating a release." >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
git fetch origin main --tags
|
|
61
|
+
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then
|
|
62
|
+
echo "Local main must match origin/main before creating a release." >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
uv run pytest
|
|
67
|
+
uv run bumpver update "--${version_kind}" --ignore-vcs-tag --no-fetch
|
|
68
|
+
version="$(uv run python -c 'from pytest_docker_compose import __version__; print(__version__)')"
|
|
69
|
+
|
|
70
|
+
uv run just release-notes "${version}"
|
|
71
|
+
git push origin main
|
|
72
|
+
git push origin "${version}"
|
|
73
|
+
|
|
74
|
+
echo
|
|
75
|
+
echo "Release ${version} pushed. Once GitHub creates the release, publish its notes with:"
|
|
76
|
+
echo " uv run just publish-release-notes ${version}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: pytest-docker-compose-v2
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Manages Docker containers during your integration tests
|
|
5
5
|
Project-URL: repository, https://github.com/radusuciu/pytest-docker-compose-v2
|
|
6
6
|
Author: Radu Suciu, Thomas Meckel, Roald Storm, Phoenix Zerin
|
|
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
22
22
|
Classifier: Topic :: Software Development :: Testing
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: pytest<10,>=7.2.2
|
|
25
|
-
Requires-Dist: python-on-whales<1,>=0.
|
|
25
|
+
Requires-Dist: python-on-whales<1,>=0.71.0
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
|
|
28
28
|
[](https://pypi.python.org/pypi/pytest-docker-compose-v2/)
|
|
@@ -103,7 +103,53 @@ The fixtures called `[scope]_scoped_container_getter` will wait until every cont
|
|
|
103
103
|
|
|
104
104
|
However, just because a container is up does not mean that the services running on it are ready to accept incoming requests yet!
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
#### Option 1: Using Docker Compose Healthchecks (Recommended)
|
|
107
|
+
|
|
108
|
+
The plugin can use Docker Compose's native `--wait` functionality with healthchecks defined in your `docker-compose.yml`. This lets Docker Compose handle waiting for services to be ready.
|
|
109
|
+
|
|
110
|
+
First, define healthchecks in your `docker-compose.yml`:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
services:
|
|
114
|
+
my_api_service:
|
|
115
|
+
build: ./api
|
|
116
|
+
ports:
|
|
117
|
+
- "5000:5000"
|
|
118
|
+
depends_on:
|
|
119
|
+
my_db:
|
|
120
|
+
condition: service_healthy
|
|
121
|
+
healthcheck:
|
|
122
|
+
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
|
|
123
|
+
interval: 5s
|
|
124
|
+
timeout: 5s
|
|
125
|
+
retries: 10
|
|
126
|
+
start_period: 10s
|
|
127
|
+
my_db:
|
|
128
|
+
image: postgres:15
|
|
129
|
+
healthcheck:
|
|
130
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
131
|
+
interval: 5s
|
|
132
|
+
timeout: 5s
|
|
133
|
+
retries: 10
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Then opt in to waiting when you run pytest:
|
|
137
|
+
|
|
138
|
+
```shell
|
|
139
|
+
pytest --docker-compose-wait
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
You can also specify a timeout (in seconds):
|
|
143
|
+
|
|
144
|
+
```shell
|
|
145
|
+
pytest --docker-compose-wait --docker-compose-wait-timeout=120
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Waiting remains opt-in for backward compatibility. It is planned to become the default in version 1.0.
|
|
149
|
+
|
|
150
|
+
#### Option 2: Python-based Wait Fixtures
|
|
151
|
+
|
|
152
|
+
If your tests need to wait for a particular condition (for example, to wait for an HTTP health check endpoint to send back a 200 response), you can implement custom wait logic in your fixtures.
|
|
107
153
|
|
|
108
154
|
Here's an example of a fixture called `wait_for_api` that waits for an HTTP service to come online before a test called `test_read_and_write` can run.
|
|
109
155
|
|
|
@@ -221,5 +267,47 @@ pytest --docker-compose-remove-volumes
|
|
|
221
267
|
|
|
222
268
|
This option will be ignored if the plugin is not used. Again, this option can also be added to the `pytest.ini` file.
|
|
223
269
|
|
|
270
|
+
### Command Line Options Summary
|
|
271
|
+
|
|
272
|
+
| Option | Description |
|
|
273
|
+
|--------|-------------|
|
|
274
|
+
| `--docker-compose` | Path to docker-compose.yml file or directory containing one. Multiple files can be specified with commas. |
|
|
275
|
+
| `--docker-compose-no-build` | Skip building Docker images before running tests. |
|
|
276
|
+
| `--docker-compose-remove-volumes` | Remove container volumes after tests complete. |
|
|
277
|
+
| `--use-running-containers` | Use already running containers instead of starting new ones. |
|
|
278
|
+
| `--docker-compose-wait` | Wait for services to be healthy before running tests (requires healthcheck definitions). |
|
|
279
|
+
| `--docker-compose-wait-timeout` | Timeout in seconds when waiting for services to be healthy. |
|
|
280
|
+
|
|
224
281
|
For more examples on how to use this plugin look at the testing suite of this plugin itself! It will give you some examples for configuring `pyproject.toml` and how to use the different fixtures to run docker containers.
|
|
225
282
|
|
|
283
|
+
## Releasing
|
|
284
|
+
|
|
285
|
+
Release commands are managed with `just`, which is installed by the development
|
|
286
|
+
dependency group:
|
|
287
|
+
|
|
288
|
+
```shell
|
|
289
|
+
uv sync
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Preview the release notes for a version without modifying the repository:
|
|
293
|
+
|
|
294
|
+
```shell
|
|
295
|
+
uv run just release-notes 0.3.0
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Create and push a release from a clean, up-to-date `main` branch by choosing a
|
|
299
|
+
semantic version increment:
|
|
300
|
+
|
|
301
|
+
```shell
|
|
302
|
+
uv run just release patch
|
|
303
|
+
uv run just release minor
|
|
304
|
+
uv run just release major
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The command runs the tests, updates the package version, creates the version
|
|
308
|
+
commit and tag, and pushes both. Once GitHub Actions has created the GitHub
|
|
309
|
+
Release, its generated notes can be added with:
|
|
310
|
+
|
|
311
|
+
```shell
|
|
312
|
+
uv run just publish-release-notes 0.3.0
|
|
313
|
+
```
|
|
@@ -76,7 +76,53 @@ The fixtures called `[scope]_scoped_container_getter` will wait until every cont
|
|
|
76
76
|
|
|
77
77
|
However, just because a container is up does not mean that the services running on it are ready to accept incoming requests yet!
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
#### Option 1: Using Docker Compose Healthchecks (Recommended)
|
|
80
|
+
|
|
81
|
+
The plugin can use Docker Compose's native `--wait` functionality with healthchecks defined in your `docker-compose.yml`. This lets Docker Compose handle waiting for services to be ready.
|
|
82
|
+
|
|
83
|
+
First, define healthchecks in your `docker-compose.yml`:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
services:
|
|
87
|
+
my_api_service:
|
|
88
|
+
build: ./api
|
|
89
|
+
ports:
|
|
90
|
+
- "5000:5000"
|
|
91
|
+
depends_on:
|
|
92
|
+
my_db:
|
|
93
|
+
condition: service_healthy
|
|
94
|
+
healthcheck:
|
|
95
|
+
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
|
|
96
|
+
interval: 5s
|
|
97
|
+
timeout: 5s
|
|
98
|
+
retries: 10
|
|
99
|
+
start_period: 10s
|
|
100
|
+
my_db:
|
|
101
|
+
image: postgres:15
|
|
102
|
+
healthcheck:
|
|
103
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
104
|
+
interval: 5s
|
|
105
|
+
timeout: 5s
|
|
106
|
+
retries: 10
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Then opt in to waiting when you run pytest:
|
|
110
|
+
|
|
111
|
+
```shell
|
|
112
|
+
pytest --docker-compose-wait
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
You can also specify a timeout (in seconds):
|
|
116
|
+
|
|
117
|
+
```shell
|
|
118
|
+
pytest --docker-compose-wait --docker-compose-wait-timeout=120
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Waiting remains opt-in for backward compatibility. It is planned to become the default in version 1.0.
|
|
122
|
+
|
|
123
|
+
#### Option 2: Python-based Wait Fixtures
|
|
124
|
+
|
|
125
|
+
If your tests need to wait for a particular condition (for example, to wait for an HTTP health check endpoint to send back a 200 response), you can implement custom wait logic in your fixtures.
|
|
80
126
|
|
|
81
127
|
Here's an example of a fixture called `wait_for_api` that waits for an HTTP service to come online before a test called `test_read_and_write` can run.
|
|
82
128
|
|
|
@@ -194,5 +240,47 @@ pytest --docker-compose-remove-volumes
|
|
|
194
240
|
|
|
195
241
|
This option will be ignored if the plugin is not used. Again, this option can also be added to the `pytest.ini` file.
|
|
196
242
|
|
|
243
|
+
### Command Line Options Summary
|
|
244
|
+
|
|
245
|
+
| Option | Description |
|
|
246
|
+
|--------|-------------|
|
|
247
|
+
| `--docker-compose` | Path to docker-compose.yml file or directory containing one. Multiple files can be specified with commas. |
|
|
248
|
+
| `--docker-compose-no-build` | Skip building Docker images before running tests. |
|
|
249
|
+
| `--docker-compose-remove-volumes` | Remove container volumes after tests complete. |
|
|
250
|
+
| `--use-running-containers` | Use already running containers instead of starting new ones. |
|
|
251
|
+
| `--docker-compose-wait` | Wait for services to be healthy before running tests (requires healthcheck definitions). |
|
|
252
|
+
| `--docker-compose-wait-timeout` | Timeout in seconds when waiting for services to be healthy. |
|
|
253
|
+
|
|
197
254
|
For more examples on how to use this plugin look at the testing suite of this plugin itself! It will give you some examples for configuring `pyproject.toml` and how to use the different fixtures to run docker containers.
|
|
198
255
|
|
|
256
|
+
## Releasing
|
|
257
|
+
|
|
258
|
+
Release commands are managed with `just`, which is installed by the development
|
|
259
|
+
dependency group:
|
|
260
|
+
|
|
261
|
+
```shell
|
|
262
|
+
uv sync
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Preview the release notes for a version without modifying the repository:
|
|
266
|
+
|
|
267
|
+
```shell
|
|
268
|
+
uv run just release-notes 0.3.0
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Create and push a release from a clean, up-to-date `main` branch by choosing a
|
|
272
|
+
semantic version increment:
|
|
273
|
+
|
|
274
|
+
```shell
|
|
275
|
+
uv run just release patch
|
|
276
|
+
uv run just release minor
|
|
277
|
+
uv run just release major
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The command runs the tests, updates the package version, creates the version
|
|
281
|
+
commit and tag, and pushes both. Once GitHub Actions has created the GitHub
|
|
282
|
+
Release, its generated notes can be added with:
|
|
283
|
+
|
|
284
|
+
```shell
|
|
285
|
+
uv run just publish-release-notes 0.3.0
|
|
286
|
+
```
|
|
@@ -10,7 +10,7 @@ authors = [
|
|
|
10
10
|
]
|
|
11
11
|
dependencies = [
|
|
12
12
|
"pytest>=7.2.2,<10",
|
|
13
|
-
"python-on-whales>=0.
|
|
13
|
+
"python-on-whales>=0.71.0,<1"
|
|
14
14
|
]
|
|
15
15
|
requires-python = ">=3.10"
|
|
16
16
|
readme = "README.md"
|
|
@@ -58,6 +58,7 @@ dev = [
|
|
|
58
58
|
"tox>=4.30.3",
|
|
59
59
|
"tox-uv>=1.28.1",
|
|
60
60
|
"pytest>=8,<10",
|
|
61
|
+
"rust-just>=1.58.0",
|
|
61
62
|
]
|
|
62
63
|
|
|
63
64
|
[tool.hatch.version]
|
|
@@ -67,23 +68,24 @@ path = "pytest_docker_compose/__init__.py"
|
|
|
67
68
|
packages = ["pytest_docker_compose"]
|
|
68
69
|
|
|
69
70
|
[tool.pytest.ini_options]
|
|
70
|
-
addopts = "-m 'not (should_fail or multiple_compose_files)' '--docker-compose' './tests/pytest_docker_compose_tests/my_network' '--docker-compose-no-build'"
|
|
71
|
+
addopts = "-m 'not (should_fail or multiple_compose_files or wait_for_healthcheck)' '--docker-compose' './tests/pytest_docker_compose_tests/my_network' '--docker-compose-no-build'"
|
|
71
72
|
markers = [
|
|
72
73
|
"should_fail: marks a set of test that should throw an error when run",
|
|
73
74
|
"multiple_compose_files: marks a test that uses more than one compose file",
|
|
75
|
+
"wait_for_healthcheck: marks tests that use --docker-compose-wait with healthchecks",
|
|
74
76
|
]
|
|
75
77
|
minversion = "7.2"
|
|
76
78
|
|
|
77
79
|
[tool.ruff]
|
|
78
80
|
line-length = 88
|
|
79
|
-
target-version = "
|
|
81
|
+
target-version = "py310"
|
|
80
82
|
|
|
81
83
|
[tool.ruff.lint.mccabe]
|
|
82
84
|
# Unlike Flake8, default to a complexity level of 10.
|
|
83
85
|
max-complexity = 10
|
|
84
86
|
|
|
85
87
|
[tool.bumpver]
|
|
86
|
-
current_version = "0.
|
|
88
|
+
current_version = "0.3.0"
|
|
87
89
|
version_pattern = "MAJOR.MINOR.PATCH[GITHASH]"
|
|
88
90
|
commit_message = "bump version {old_version} -> {new_version}"
|
|
89
91
|
commit = true
|
|
@@ -122,4 +124,5 @@ commands=
|
|
|
122
124
|
docker compose -f tests/pytest_docker_compose_tests/my_network/docker-compose.yml up -d
|
|
123
125
|
pytest --use-running-containers
|
|
124
126
|
docker compose -f tests/pytest_docker_compose_tests/my_network/docker-compose.yml down -v
|
|
127
|
+
pytest -m wait_for_healthcheck --docker-compose ./tests/pytest_docker_compose_tests/my_network --docker-compose-wait
|
|
125
128
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
{pytest_docker_compose_v2-0.2.0 → pytest_docker_compose_v2-0.3.0}/pytest_docker_compose/plugin.py
RENAMED
|
@@ -11,8 +11,6 @@ from python_on_whales.components.container.cli_wrapper import Container
|
|
|
11
11
|
class ContainersAlreadyExist(Exception):
|
|
12
12
|
"""Raised when running containers are unexpectedly found"""
|
|
13
13
|
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
14
|
|
|
17
15
|
__all__ = [
|
|
18
16
|
"DockerComposePlugin",
|
|
@@ -125,6 +123,21 @@ class DockerComposePlugin:
|
|
|
125
123
|
"instead of calling 'docker-compose up'",
|
|
126
124
|
)
|
|
127
125
|
|
|
126
|
+
group.addoption(
|
|
127
|
+
"--docker-compose-wait",
|
|
128
|
+
action="store_true",
|
|
129
|
+
default=False,
|
|
130
|
+
help="Wait for services to be healthy before running tests "
|
|
131
|
+
"(requires healthcheck definitions in docker-compose.yml)",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
group.addoption(
|
|
135
|
+
"--docker-compose-wait-timeout",
|
|
136
|
+
type=int,
|
|
137
|
+
default=None,
|
|
138
|
+
help="Timeout in seconds when waiting for services to be healthy",
|
|
139
|
+
)
|
|
140
|
+
|
|
128
141
|
@pytest.fixture(scope="session")
|
|
129
142
|
def docker_project(self, request):
|
|
130
143
|
"""
|
|
@@ -144,10 +157,8 @@ class DockerComposePlugin:
|
|
|
144
157
|
|
|
145
158
|
if not docker_compose.is_file():
|
|
146
159
|
raise ValueError(
|
|
147
|
-
"Unable to find `{docker_compose}` "
|
|
148
|
-
"for integration tests."
|
|
149
|
-
docker_compose=docker_compose.absolute(),
|
|
150
|
-
),
|
|
160
|
+
f"Unable to find `{docker_compose.absolute()}` "
|
|
161
|
+
"for integration tests.",
|
|
151
162
|
)
|
|
152
163
|
|
|
153
164
|
compose_files.append(docker_compose)
|
|
@@ -183,11 +194,14 @@ class DockerComposePlugin:
|
|
|
183
194
|
)
|
|
184
195
|
)
|
|
185
196
|
current_containers = project.compose.ps()
|
|
186
|
-
project.compose.up(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
197
|
+
project.compose.up(
|
|
198
|
+
detach=True,
|
|
199
|
+
quiet=True,
|
|
200
|
+
wait=request.config.getoption("--docker-compose-wait"),
|
|
201
|
+
wait_timeout=request.config.getoption("--docker-compose-wait-timeout"),
|
|
202
|
+
)
|
|
203
|
+
containers = list(project.compose.config().services.keys())
|
|
204
|
+
if len(current_containers) != len(containers):
|
|
191
205
|
warnings.warn(
|
|
192
206
|
UserWarning(
|
|
193
207
|
"You used the '--use-running-containers' but "
|
|
@@ -197,11 +211,9 @@ class DockerComposePlugin:
|
|
|
197
211
|
)
|
|
198
212
|
else:
|
|
199
213
|
if any(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if container.state.running
|
|
204
|
-
)
|
|
214
|
+
container
|
|
215
|
+
for container in project.compose.ps()
|
|
216
|
+
if container.state.running
|
|
205
217
|
):
|
|
206
218
|
raise ContainersAlreadyExist(
|
|
207
219
|
"There are already existing containers, please remove all "
|
|
@@ -228,18 +240,21 @@ class DockerComposePlugin:
|
|
|
228
240
|
now = datetime.now(timezone.utc)
|
|
229
241
|
if not request.config.getoption("--use-running-containers"):
|
|
230
242
|
if any(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if container.state.running
|
|
235
|
-
)
|
|
243
|
+
container
|
|
244
|
+
for container in docker_project.compose.ps()
|
|
245
|
+
if container.state.running
|
|
236
246
|
):
|
|
237
247
|
raise ContainersAlreadyExist(
|
|
238
248
|
"pytest-docker-compose tried to start containers but there are"
|
|
239
|
-
" already running containers:
|
|
240
|
-
" tests wrong"
|
|
249
|
+
f" already running containers: {docker_project.compose.ps()},"
|
|
250
|
+
" you probably scoped your tests wrong"
|
|
241
251
|
)
|
|
242
|
-
docker_project.compose.up(
|
|
252
|
+
docker_project.compose.up(
|
|
253
|
+
detach=True,
|
|
254
|
+
quiet=True,
|
|
255
|
+
wait=request.config.getoption("--docker-compose-wait"),
|
|
256
|
+
wait_timeout=request.config.getoption("--docker-compose-wait-timeout"),
|
|
257
|
+
)
|
|
243
258
|
if not any(docker_project.compose.ps()):
|
|
244
259
|
raise ValueError("`docker-compose` didn't launch any containers!")
|
|
245
260
|
|
|
@@ -249,7 +264,7 @@ class DockerComposePlugin:
|
|
|
249
264
|
if request.config.getoption("--verbose"):
|
|
250
265
|
containers = docker_project.compose.ps()
|
|
251
266
|
for container in sorted(containers, key=lambda c: c.name):
|
|
252
|
-
header = "Logs from {name}:"
|
|
267
|
+
header = f"Logs from {container.name}:"
|
|
253
268
|
print(header, "\n", "=" * len(header))
|
|
254
269
|
print(
|
|
255
270
|
container.logs(since=now) or "(no logs)",
|
|
@@ -261,16 +276,13 @@ class DockerComposePlugin:
|
|
|
261
276
|
volumes=request.config.getoption("--docker-compose-remove-volumes")
|
|
262
277
|
)
|
|
263
278
|
|
|
264
|
-
scoped_containers_fixture.__wrapped__.__doc__ =
|
|
265
|
-
"""
|
|
279
|
+
scoped_containers_fixture.__wrapped__.__doc__ = f"""
|
|
266
280
|
Spins up the containers for the Docker project and returns an
|
|
267
281
|
object that can retrieve the containers. The returned containers
|
|
268
282
|
all have one additional attribute called network_info to simplify
|
|
269
283
|
accessing the hostnames and exposed port numbers for each container.
|
|
270
|
-
This set of containers is scoped to '
|
|
284
|
+
This set of containers is scoped to '{scope}'
|
|
271
285
|
"""
|
|
272
|
-
% scope
|
|
273
|
-
)
|
|
274
286
|
return scoped_containers_fixture
|
|
275
287
|
|
|
276
288
|
|
|
@@ -307,8 +319,8 @@ class ContainerGetter:
|
|
|
307
319
|
if not containers_running.get(key):
|
|
308
320
|
warnings.warn(
|
|
309
321
|
UserWarning(
|
|
310
|
-
"The service '
|
|
311
|
-
"it stopped with '
|
|
322
|
+
f"The service '{key}' only has a stopped container, "
|
|
323
|
+
f"it stopped with '{container.state.status}'"
|
|
312
324
|
)
|
|
313
325
|
)
|
|
314
326
|
network_info = create_network_info_for_container(container)
|
pytest_docker_compose_v2-0.3.0/tests/pytest_docker_compose_tests/my_network/docker-compose.yml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
services:
|
|
2
|
+
my_api_service:
|
|
3
|
+
build: ./a_buildable_container
|
|
4
|
+
ports:
|
|
5
|
+
- "5000:5000"
|
|
6
|
+
depends_on:
|
|
7
|
+
my_db:
|
|
8
|
+
condition: service_healthy
|
|
9
|
+
my_short_lived_service:
|
|
10
|
+
condition: service_completed_successfully
|
|
11
|
+
restart: on-failure
|
|
12
|
+
healthcheck:
|
|
13
|
+
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/')"]
|
|
14
|
+
interval: 2s
|
|
15
|
+
timeout: 5s
|
|
16
|
+
retries: 10
|
|
17
|
+
start_period: 5s
|
|
18
|
+
my_db:
|
|
19
|
+
image: postgres:11.2-alpine
|
|
20
|
+
ports:
|
|
21
|
+
- "5432:5432"
|
|
22
|
+
environment:
|
|
23
|
+
POSTGRES_HOST_AUTH_METHOD: trust
|
|
24
|
+
healthcheck:
|
|
25
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
26
|
+
interval: 2s
|
|
27
|
+
timeout: 5s
|
|
28
|
+
retries: 10
|
|
29
|
+
start_period: 5s
|
|
30
|
+
my_short_lived_service:
|
|
31
|
+
build: ./a_buildable_container
|
|
32
|
+
entrypoint: /bin/echo
|
|
33
|
+
command: "Echoing"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for the --docker-compose-wait feature.
|
|
3
|
+
|
|
4
|
+
These tests verify that when --docker-compose-wait is used, containers
|
|
5
|
+
are healthy (based on their healthcheck definitions) before tests run.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import requests
|
|
10
|
+
|
|
11
|
+
pytestmark = pytest.mark.wait_for_healthcheck
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(scope="function")
|
|
15
|
+
def api_service(function_scoped_container_getter):
|
|
16
|
+
"""Get the API service container."""
|
|
17
|
+
container = function_scoped_container_getter.get("my_api_service")
|
|
18
|
+
assert hasattr(container, "network_info")
|
|
19
|
+
assert container.network_info
|
|
20
|
+
return container
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_container_is_healthy_when_wait_flag_used(api_service):
|
|
24
|
+
"""
|
|
25
|
+
When --docker-compose-wait is used, the container should already be healthy
|
|
26
|
+
by the time the test runs, meaning we can immediately make requests without
|
|
27
|
+
any retry logic.
|
|
28
|
+
"""
|
|
29
|
+
network_info = api_service.network_info[0]
|
|
30
|
+
api_url = f"http://{network_info.hostname}:{network_info.host_port}/"
|
|
31
|
+
|
|
32
|
+
# With --docker-compose-wait, the service should be immediately available
|
|
33
|
+
# without needing retry logic
|
|
34
|
+
response = requests.get(api_url, timeout=5)
|
|
35
|
+
assert response.status_code == 200
|
|
36
|
+
assert response.json() == {"Hello": "World"}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_db_container_is_healthy(function_scoped_container_getter):
|
|
40
|
+
"""
|
|
41
|
+
Verify the database container is also healthy when --docker-compose-wait is used.
|
|
42
|
+
"""
|
|
43
|
+
container = function_scoped_container_getter.get("my_db")
|
|
44
|
+
# Container should be running and healthy
|
|
45
|
+
assert container.state.running
|
|
46
|
+
# With --docker-compose-wait, the health status should be "healthy"
|
|
47
|
+
assert container.state.health is not None
|
|
48
|
+
assert container.state.health.status == "healthy"
|