7 Commits
main ... 1.4.x

Author SHA1 Message Date
ed1e8650db Merge pull request #1244 from mokibit/1.4-backport-1243
1.4.x backport: Fix dockerfile definition if directory name ends with ".git"
2025-06-17 23:20:06 +03:00
8e2cd2bab8 Fix dockerfile definition if directory name ends with ".git"
After changes in 92f0a8583a, the
dockerfile parameter is igored if the (local) work directory's name ends
in `.git`.
This commit fixes the regression and adds more tests.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-17 23:10:17 +03:00
b37076bc5e Merge pull request #1233 from p12tic/release
Release notes for 1.4.1
2025-06-05 17:15:24 +03:00
3db72df49d Release notes for 1.4.1
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 17:09:50 +03:00
189c086d5b Merge pull request #1232 from p12tic/1.4-backport-1231
[1.4 backports] Fix relative host path resolution for volume bind mount source
2025-06-05 17:08:16 +03:00
32b3d26ab1 Add newsfragment
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 17:00:37 +03:00
35a66f5a8b Fix relative host path resolution for volume bind mount source
e03d675b9b broke relative host path
resolution by deleting os.chdir(). After this commit current working
directory is not relevant anymore.

Fixes e03d675b9b.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-05 16:58:42 +03:00
133 changed files with 807 additions and 1999 deletions

View File

@ -14,19 +14,12 @@ jobs:
options: --privileged --cgroupns=host
steps:
- uses: actions/checkout@v4
- name: Install dependencies
- name: Analysing the code with ruff
run: |
set -e
pip install -r test-requirements.txt
- name: Analysing the code using ruff
run: |
set -e
ruff format --check
ruff check
- name: Analysing the code using mypy
run: |
set -e
mypy .
- name: Analysing the code with pylint
run: |
pylint podman_compose.py

View File

@ -19,12 +19,11 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
$ cd podman-compose
```
2. (OPTIONAL) Create a Python virtual environment. Example using python builtin
`venv` module:
2. (OPTIONAL) Create a Python virtual environment. Example using
[virtualenv wrapper](https://virtualenvwrapper.readthedocs.io/en/latest/):
```shell
$ python3 -m venv .venv
$ . .venv/bin/activate
$ mkvirtualenv podman-compose
```
3. Install the project runtime and development requirements:
@ -61,25 +60,9 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
- Make sure you include a `Signed-off-by` message in your commits.
Read [this guide](https://github.com/containers/common/blob/main/CONTRIBUTING.md#sign-your-prs)
to learn how to sign your commits.
- In the commit message body, reference the Issue ID that your code fixes and a brief description of the changes.
Example:
```
Allow empty network
<description, such as links to the compose spec and so on>
Fixes https://github.com/containers/podman-compose/issues/516
```
- If your commit requires a refactoring, first do the refactoring and
commit it separately before starting feature work. This makes the
pull request easier to review. Additionally, pull request will be
less risky, because if it breaks something, it's way easier to
isolate the offending code, understand what's broken and fix it.
Due to the latter reason it's best to commit in as many independent
commits as reasonable.
This will result in pull requests being merged much faster.
- In the commit message, reference the Issue ID that your code fixes and a brief description of
the changes.
Example: `Fixes #516: Allow empty network`
9. Open a pull request to `containers/podman-compose` and wait for a maintainer to review your work.
## Adding new commands

View File

@ -68,23 +68,7 @@ Or latest development version from GitHub:
pip3 install https://github.com/containers/podman-compose/archive/main.tar.gz
```
### Package repositories
podman-compose is available from the following package repositories:
Debian:
```bash
sudo apt install podman-compose
```
Fedora (starting from f31) repositories:
```bash
sudo dnf install podman-compose
```
Homebrew:
### Homebrew
```bash
brew install podman-compose
@ -110,22 +94,51 @@ curl -o ~/.local/bin/podman-compose https://raw.githubusercontent.com/containers
chmod +x ~/.local/bin/podman-compose
```
or install from Fedora (starting from f31) repositories:
```bash
sudo dnf install podman-compose
```
## Basic Usage
We have included fully functional sample stacks inside `examples/` directory.
You can get more examples from [awesome-compose](https://github.com/docker/awesome-compose).
A quick example would be
```bash
cd examples/busybox
podman-compose --help
podman-compose up --help
podman-compose up
```
A more rich example can be found in [examples/awx3](examples/awx3)
which have
- A Postgres Database
- RabbitMQ server
- MemCached server
- a django web server
- a django tasks
When testing the `AWX3` example, if you got errors, just wait for db migrations to end.
There is also AWX 17.1.0
## Tests
podman-compose is tested via unit and integration tests.
Inside `tests/` directory we have many useless docker-compose stacks
that are meant to test as many cases as we can to make sure we are compatible
Unit tests can be run via the following:
### Unit tests with unittest
run a unittest with following command
```shell
python3 -m unittest discover tests/unit
```
Integration tests can be run via the following:
```shell
python3 -m unittest discover tests/integration
```
# Contributing guide
If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section

View File

@ -27,22 +27,6 @@ services:
For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/).
## Secrets
The following extension keys are available under `secret` configuration:
x-podman.relabel - Configure SELinux relabeling
For example, the following configures custom-secret to use mount with private and unshared content.
Only the current container can use a private volume.
```yml
secrets:
custom-secret:
x-podman.relabel: Z
```
For explanations of these extensions, please refer to the [podman-run --volume documentation](https://docs.podman.io/en/latest/markdown/podman-run.1.html#volume-v-source-volume-host-dir-container-dir-options)).
## Network management
The following extension keys are available under network configuration:
@ -139,44 +123,6 @@ The options to the network modes are passed to the `--network` option of the `po
as-is.
## Docker Compose Compatibility
podman-compose aims to be compatible with docker-compose, but there are some differences in
behavior and features. The following sections describe how to enable compatibility with docker-compose
and how to handle some of the differences.
Compatibility settings can either be set explicitly as described below, or by setting the `docker_compose_compat` meta
settings to `true` under the global `x-podman` key:
```yaml
x-podman:
docker_compose_compat: true
```
This will enable all compatibility settings described below, and is equivalent to setting each of them to `true`.
This setting can also be changed by setting the `PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT` environment variable.
## Compatibility of name separators between docker-compose and podman-compose
Currently, podman-compose is using underscores (`_` character) as a separator in names of
containers, images, etc., while docker-compose has switched to hyphens (`-` character). This setting
allows to switch podman-compose to use hyphens as well.
To enable compatibility between docker-compose and podman-compose, specify
`name_separator_compat: true` under global `x-podman` key:
```
x-podman:
name_separator_compat: true
```
By default `name_separator_compat` is `false`. This will change to `true` at some point and the
setting will be removed.
This setting can also be changed by setting `PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT` environment
variable.
## Compatibility of default network names between docker-compose and podman-compose
Current versions of podman-compose may produce different default external network names than
@ -194,9 +140,6 @@ x-podman:
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
setting will be removed.
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_NAME_COMPAT` environment
variable.
## Compatibility of default network behavior between docker-compose and podman-compose
When there is no network defined (neither network-mode nor networks) in service,
@ -217,9 +160,6 @@ x-podman:
default_net_behavior_compat: true
```
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_BEHAVIOR_COMPAT` environment
variable.
## Custom pods management
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
@ -239,9 +179,6 @@ x-podman:
in_pod: false
```
This setting can also be changed by setting `PODMAN_COMPOSE_IN_POD` environment
variable.
It is also possible to override the default arguments for pod creation that are
used when --pod-args is not passed on the command line:
```yml
@ -255,6 +192,3 @@ x-podman:
```
When not set in docker-compose.yml or on the command line, the pod args default
to `["--infra=false", "--share="]`.
This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment
variable.

View File

@ -3,8 +3,8 @@
import asyncio # noqa: F401
import os
import aioredis # type: ignore[import-not-found]
from aiohttp import web # type: ignore[import-not-found]
import aioredis
from aiohttp import web
REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
@ -16,13 +16,13 @@ routes = web.RouteTableDef()
@routes.get("/")
async def hello(request: web.Request) -> web.Response: # pylint: disable=unused-argument
async def hello(request): # pylint: disable=unused-argument
counter = await redis.incr("mycounter")
return web.Response(text=f"counter={counter}")
@routes.get("/hello.json")
async def hello_json(request: web.Request) -> web.Response: # pylint: disable=unused-argument
async def hello_json(request): # pylint: disable=unused-argument
counter = await redis.incr("mycounter")
data = {"counter": counter}
return web.json_response(data)
@ -31,7 +31,7 @@ async def hello_json(request: web.Request) -> web.Response: # pylint: disable=u
app.add_routes(routes)
def main() -> None:
def main():
web.run_app(app, port=8080)

View File

@ -1 +0,0 @@
- Add unregister command to remove systemd service registration (`podman-compose systemd -a unregister`)

View File

@ -1 +0,0 @@
- Change behaviour of `--in-pod` to handle custom pod names instead of only disabling pod feature

View File

@ -1 +0,0 @@
- Add new docker_compose_compat x-podman meta setting to enable all Docker Compose compatibility settings

View File

@ -1 +0,0 @@
Add support for environment variable interpolation for YAML keys.

View File

@ -1 +0,0 @@
Fixed build ssh path to a local SSH key, to be relative to the directory of compose file.

View File

@ -1 +0,0 @@
Fixed support for CMD healthchecks to run using the given command directly and not using `/bin/sh -c`.

View File

@ -1 +0,0 @@
Implemented short syntax for environment variables set in `.env` for compose.yml "environment:" section.

View File

@ -1 +0,0 @@
Fixed regression of log output including "text" in detached mode.

View File

@ -1 +0,0 @@
Hide the stack trace on a YAML parse error.

View File

@ -1 +0,0 @@
Added `io.podman.compose.service` label to created containers. It contains the same value as com.docker.compose.service.

View File

@ -1 +0,0 @@
- Add new name_separator_compat x-podman setting to change name separator to hyphen, same as Docker Compose

View File

@ -1 +0,0 @@
- Add relabel option to secret to make possible to read the secret file by the contained process.

View File

@ -1 +0,0 @@
- Add support for setting x-podman values using PODMAN_COMPOSE_* environment variables.

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +1,3 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools"]
[project]
name = "podman-compose"
authors = [
{ email = "alsadi@gmail.com", name = "Muayyad Alsadi" },
]
description = "A script to run docker-compose.yml using podman"
dependencies = [
"python-dotenv",
"pyyaml",
]
requires-python = ">=3.9"
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Build Tools",
]
keywords = [
"podman",
"podman-compose",
]
license = "GPL-2.0-only"
dynamic = ["version", "readme"]
[project.urls]
homepage = "https://github.com/containers/podman-compose"
[project.optional-dependencies]
devel = [
"coverage",
"parameterized",
"pre-commit",
"ruff",
]
[project.scripts]
podman-compose = "podman_compose:main"
[tool.setuptools]
py-modules = ["podman_compose"]
[tool.setuptools.dynamic]
readme = {file = ["README.md"], content-type = "text/markdown"}
version = {attr = "podman_compose.__version__"}
[tool.ruff]
line-length = 100
target-version = "py38"
@ -109,21 +53,3 @@ quote-style = "preserve"
directory = "misc"
name = "Misc"
showcontent = true
[tool.mypy]
python_version = "3.9"
namespace_packages = true
explicit_package_bases = true
pretty = true
warn_redundant_casts = true
disallow_untyped_calls = false
disallow_untyped_defs = true
no_implicit_optional = true
mypy_path = "$MYPY_CONFIG_FILE_DIR"
exclude = "build"
[[tool.mypy.overrides]]
module = [
"parameterized.*",
]
ignore_missing_imports = true

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash
./scripts/uninstall.sh
./scripts/clean_up.sh
pyproject-build
python3 setup.py register
python3 setup.py sdist bdist_wheel
twine upload dist/*

View File

@ -1,5 +1,11 @@
[bdist_wheel]
universal = 1
[metadata]
version = attr: podman_compose.__version__
[flake8]
# The GitHub editor is 127 chars wide
max-line-length=127
# These are not being followed yet
ignore=E222,E231,E272,E713,W503
ignore=E222,E231,E272,E713,W503

49
setup.py Normal file
View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: GPL-2.0
import os
from setuptools import setup
try:
README = open(os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8").read()
except: # noqa: E722 # pylint: disable=bare-except
README = ""
setup(
name="podman-compose",
description="A script to run docker-compose.yml using podman",
long_description=README,
long_description_content_type="text/markdown",
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Development Status :: 3 - Alpha",
"Topic :: Software Development :: Build Tools",
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
],
keywords="podman, podman-compose",
author="Muayyad Alsadi",
author_email="alsadi@gmail.com",
url="https://github.com/containers/podman-compose",
py_modules=["podman_compose"],
entry_points={"console_scripts": ["podman-compose = podman_compose:main"]},
include_package_data=True,
license="GPL-2.0-only",
install_requires=[
"pyyaml",
"python-dotenv",
],
extras_require={"devel": ["ruff", "pre-commit", "coverage", "parameterized"]},
# test_suite='tests',
# tests_require=[
# 'coverage',
# 'tox',
# ]
)

View File

@ -1,15 +1,10 @@
-e .
coverage==7.4.3
cryptography==44.0.3
parameterized==0.9.0
pytest==8.0.2
tox==4.13.0
mypy==1.15.0
ruff==0.11.11
ruff==0.3.1
pylint==3.1.0
types-PyYAML==6.0.12.20250402
types-requests==2.32.0.20250328
types-setuptools==80.7.0.20250516
# The packages below are transitive dependencies of the packages above and are included here
# to make testing reproducible.
@ -28,7 +23,6 @@ filelock==3.13.1
iniconfig==2.0.0
isort==5.13.2
mccabe==0.7.0
mypy_extensions==1.1.0
packaging==23.2
platformdirs==4.2.0
pluggy==1.4.0
@ -37,5 +31,4 @@ python-dotenv==1.0.1
PyYAML==6.0.1
requests
tomlkit==0.12.4
typing_extensions==4.13.2
virtualenv==20.26.6

View File

@ -2,7 +2,7 @@ import os
import subprocess
def create_base_test_image() -> None:
def create_base_test_image():
subprocess.check_call(
['podman', 'build', '-t', 'nopush/podman-compose-test', '.'],
cwd=os.path.join(os.path.dirname(__file__), "base_image"),

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(failure_order: str) -> str:
def compose_yaml_path(failure_order):
return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml")
@ -25,7 +25,7 @@ class TestComposeAbort(unittest.TestCase, RunSubprocessMixin):
("exit", "none", 0),
("failure", "none", 0),
])
def test_abort(self, abort_type: str, failure_order: str, expected_exit_code: int) -> None:
def test_abort(self, abort_type, failure_order, expected_exit_code):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
""" "Returns the path to the compose file used for this test module"""
return os.path.join(test_path(), "additional_contexts", "project")
class TestComposeBuildAdditionalContexts(unittest.TestCase):
def test_build_additional_context(self) -> None:
def test_build_additional_context(self):
"""podman build should receive additional contexts as --build-context
See additional_context/project/docker-compose.yaml for context paths

View File

@ -3,12 +3,3 @@ services:
test:
build: ./context
image: build-fail-img
test_no_dockerfile:
build:
context: ./context_no_file
image: busybox
test_no_custom_dockerfile:
build:
context: ./context_no_file
dockerfile: Dockerfile-alt
image: busybox

View File

@ -22,48 +22,9 @@ class TestComposeBuildFail(unittest.TestCase, RunSubprocessMixin):
"-f",
compose_yaml_path(),
"build",
"test",
],
expected_returncode=127,
)
self.assertIn("RUN this_command_does_not_exist", str(output))
self.assertIn("this_command_does_not_exist: not found", str(error))
self.assertIn("while running runtime: exit status 127", str(error))
def test_dockerfile_does_not_exist(self):
out, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"test_no_dockerfile",
],
expected_returncode=1,
)
error = error.decode('utf-8')
result = '\n'.join(error.splitlines()[-1:])
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file")
expected = f'OSError: Dockerfile not found in {expected_path}'
self.assertEqual(expected, result)
def test_custom_dockerfile_does_not_exist(self):
out, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"test_no_custom_dockerfile",
],
expected_returncode=1,
)
error = error.decode('utf-8')
result = '\n'.join(error.splitlines()[-1:])
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file/Dockerfile-alt")
expected = f'OSError: Dockerfile not found in {expected_path}'
self.assertEqual(expected, result)

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(scenario: str) -> str:
def compose_yaml_path(scenario):
return os.path.join(
os.path.join(test_path(), "default_net_behavior"), f"docker-compose_{scenario}.yaml"
)
@ -27,13 +27,13 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
('two_nets_compat', 'default_net_behavior_default'),
('with_default_compat', 'default_net_behavior_default'),
])
def test_nethost(self, scenario: str, default_net: str) -> None:
def test_nethost(self, scenario, default_net):
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(scenario), "up", "-d"],
)
container_id_out, _ = self.run_subprocess_assert_returncode(
container_id, _ = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
@ -43,7 +43,7 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
'{{.ID}}',
],
)
container_id = container_id_out.decode('utf-8').split('\n')[0]
container_id = container_id.decode('utf-8').split('\n')[0]
output, _ = self.run_subprocess_assert_returncode(
[
"podman",

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(suffix: str = "") -> str:
def compose_yaml_path(suffix=""):
return os.path.join(os.path.join(test_path(), "deps"), f"docker-compose{suffix}.yaml")
class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps(self) -> None:
def test_deps(self):
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -37,7 +37,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_run_nodeps(self) -> None:
def test_run_nodeps(self):
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -62,7 +62,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_up_nodeps(self) -> None:
def test_up_nodeps(self):
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -89,7 +89,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_podman_compose_run(self) -> None:
def test_podman_compose_run(self):
"""
This will test depends_on as well
"""
@ -143,7 +143,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps_succeeds(self) -> None:
def test_deps_succeeds(self):
suffix = "-conditional-succeeds"
try:
output, _ = self.run_subprocess_assert_returncode([
@ -167,7 +167,7 @@ class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_deps_fails(self) -> None:
def test_deps_fails(self):
suffix = "-conditional-fails"
try:
output, _ = self.run_subprocess_assert_returncode([
@ -188,10 +188,10 @@ class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubprocessMixin):
def setUp(self) -> None:
def setUp(self):
self.podman_version = self.retrieve_podman_version()
def test_up_deps_healthy(self) -> None:
def test_up_deps_healthy(self):
suffix = "-conditional-healthy"
try:
self.run_subprocess_assert_returncode([
@ -261,6 +261,6 @@ class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubproc
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
compose_yaml_path(),
"down",
])

View File

@ -0,0 +1,2 @@
ZZVAR1='This value is overwritten by env-file-tests/.env'
ZZVAR3='This value is loaded from env-file-tests/.env'

View File

@ -1,3 +1,2 @@
ZZVAR1='This value is loaded but should be overwritten'
ZZVAR2='This value is loaded from .env in project/ directory'
ZZVAR3=TEST

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_base_path() -> str:
return os.path.join(test_path(), "env_file_tests")
def compose_base_path():
return os.path.join(test_path(), "env-file-tests")
class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
def test_path_env_file_inline(self) -> None:
def test_path_env_file_inline(self):
# Test taking env variable value directly from env-file when its path is inline path
base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -42,7 +42,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_path_env_file_flat_in_compose_file(self) -> None:
def test_path_env_file_flat_in_compose_file(self):
# Test taking env variable value from env-file/project-1.env which was declared in
# compose file's env_file
base_path = compose_base_path()
@ -74,7 +74,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_path_env_file_obj_in_compose_file(self) -> None:
def test_path_env_file_obj_in_compose_file(self):
# take variable value from env-file project-1.env which was declared in compose
# file's env_file by -path: ...
base_path = compose_base_path()
@ -106,7 +106,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_exists_optional_env_file_path_in_compose_file(self) -> None:
def test_exists_optional_env_file_path_in_compose_file(self):
# test taking env variable values from several env-files when one of them is optional
# and exists
base_path = compose_base_path()
@ -139,7 +139,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_missing_optional_env_file_path_in_compose_file(self) -> None:
def test_missing_optional_env_file_path_in_compose_file(self):
# test taking env variable values from several env-files when one of them is optional and
# is missing (silently skip it)
base_path = compose_base_path()
@ -173,7 +173,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_var_value_inline_overrides_env_file_path_inline(self) -> None:
def test_var_value_inline_overrides_env_file_path_inline(self):
# Test overriding env value when value is declared in inline command
base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -204,7 +204,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_taking_env_variables_from_env_files_from_different_directories(self) -> None:
def test_taking_env_variables_from_env_files_from_different_directories(self):
# FIXME: It is not clear what this test actually tests, but from README.md it looks like:
# Test overriding env values by directory env-files-tests/.env file values
# and only take value from project/.env, when it does not exist in env-files-tests/.env
@ -233,7 +233,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
[
'ZZVAR1=This value is loaded but should be overwritten\r',
'ZZVAR2=This value is loaded from .env in project/ directory\r',
'ZZVAR3=TEST\r',
'ZZVAR3=\r',
'',
],
)
@ -244,36 +244,3 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
path_compose_file,
"down",
])
def test_env_var_value_accessed_in_compose_file_short_syntax(self) -> None:
# Test that compose file can access the environment variable set in .env file using
# short syntax, that is: only the name of environment variable is used in "environment:" in
# compose.yml file and its value is picked up directly from .env file
# long syntax of environment variables interpolation is tested in
# tests/integration/interpolation
base_path = compose_base_path()
compose_file_path = os.path.join(base_path, "project/container-compose.short_syntax.yaml")
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"up",
"-d",
])
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"logs",
])
# ZZVAR3 was set in .env file
self.assertEqual(output, b"ZZVAR3=TEST\n")
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"down",
])

View File

@ -8,14 +8,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "env_tests"), "container-compose.yml")
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "env-tests"), "container-compose.yml")
class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
"""Test that inline environment variable overrides environment variable from compose file."""
def test_env(self) -> None:
def test_env(self):
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -50,7 +50,7 @@ class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
- https://github.com/compose-spec/compose-spec/blob/main/04-version-and-name.md
"""
def test_project_name(self) -> None:
def test_project_name(self):
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -68,7 +68,7 @@ class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_project_name_override(self) -> None:
def test_project_name_override(self):
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),

View File

@ -1,2 +0,0 @@
ZZVAR1='This value is overwritten by env_file_tests/.env'
ZZVAR3='This value is loaded from env_file_tests/.env'

View File

@ -1,10 +0,0 @@
services:
app:
image: nopush/podman-compose-test
command: ["/bin/busybox", "sh", "-c", "env | grep ZZVAR3"]
# 'env_file:' section is not used, so .env file is searched in the same directory as compose.yml
# file
environment:
# this is short syntax: podman-compose takes only this variable value from '.env' file and
# sends it to container environment
- ZZVAR3

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "exit_from"), "docker-compose.yaml")
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "exit-from"), "docker-compose.yaml")
class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
def test_exit_code_sh1(self) -> None:
def test_exit_code_sh1(self):
try:
self.run_subprocess_assert_returncode(
[
@ -33,7 +33,7 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_exit_code_sh2(self) -> None:
def test_exit_code_sh2(self):
try:
self.run_subprocess_assert_returncode(
[
@ -53,13 +53,13 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_podman_compose_exit_from(self) -> None:
def test_podman_compose_exit_from(self):
up_cmd = [
"coverage",
"run",
podman_compose_path(),
"-f",
compose_yaml_path(),
os.path.join(test_path(), "exit-from", "docker-compose.yaml"),
"up",
]

View File

@ -1 +0,0 @@

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "extends"), "docker-compose.yaml")
class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
def test_extends_service_launch_echo(self) -> None:
def test_extends_service_launch_echo(self):
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -38,7 +38,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_extends_service_launch_echo1(self) -> None:
def test_extends_service_launch_echo1(self):
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -63,7 +63,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_extends_service_launch_env1(self) -> None:
def test_extends_service_launch_env1(self):
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "extends_w_empty_service"), "docker-compose.yml")
class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_empty_service(self) -> None:
def test_extends_w_empty_service(self):
try:
self.run_subprocess_assert_returncode(
[
@ -39,7 +39,7 @@ class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_podman_compose_extends_w_empty_service(self) -> None:
def test_podman_compose_extends_w_empty_service(self):
"""
Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes an empty service. (e.g. if the file is used as placeholder for more complex

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "extends_w_file"), "docker-compose.yml")
class TestComposeExtendsWithFile(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file(self) -> None: # when file is Dockerfile for building the image
def test_extends_w_file(self): # when file is Dockerfile for building the image
try:
self.run_subprocess_assert_returncode(
[

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "extends_w_file_subdir"), "docker-compose.yml")
class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file_subdir(self) -> None: # when file is Dockerfile for building the image
def test_extends_w_file_subdir(self): # when file is Dockerfile for building the image
try:
self.run_subprocess_assert_returncode(
[
@ -39,7 +39,7 @@ class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_podman_compose_extends_w_file_subdir(self) -> None:
def test_podman_compose_extends_w_file_subdir(self):
"""
Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes a build context

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import test_path
class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
def test_compose_symlink(self) -> None:
def test_compose_symlink(self):
"""The context of podman-compose.yml should come from the same directory as the file even
if it is a symlink
"""

View File

@ -1,8 +0,0 @@
version: "3"
services:
cont:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"]
x-podman:
in_pod: custom_test_pod_name

View File

@ -6,26 +6,26 @@ import unittest
from tests.integration.test_utils import RunSubprocessMixin
def base_path() -> str:
def base_path():
"""Returns the base path for the project"""
return os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
def test_path() -> str:
def test_path():
"""Returns the path to the tests directory"""
return os.path.join(base_path(), "tests/integration")
def podman_compose_path() -> str:
def podman_compose_path():
"""Returns the path to the podman compose script"""
return os.path.join(base_path(), "podman_compose.py")
def is_root() -> bool:
def is_root():
return os.geteuid() == 0
def failure_exitcode_when_rootful() -> int:
def failure_exitcode_when_rootful():
if is_root():
return 125
return 0
@ -37,7 +37,7 @@ def failure_exitcode_when_rootful() -> int:
# Test all combinations of command line argument in_pod and compose file argument in_pod.
class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# compose file provides x-podman in_pod=false
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self) -> None:
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self):
"""
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
does not provide this option
@ -82,7 +82,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# throws an error, can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, expected_returncode=1)
def test_x_podman_in_pod_false_command_line_in_pod_true(self) -> None:
def test_x_podman_in_pod_false_command_line_in_pod_true(self):
"""
Test that podman-compose does not allow pod creating even with command line in_pod=True
when --userns and --pod are set together: throws an error
@ -115,7 +115,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_false_command_line_in_pod_false(self) -> None:
def test_x_podman_in_pod_false_command_line_in_pod_false(self):
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -160,7 +160,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self) -> None:
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self):
"""
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
command line in_pod=""
@ -207,7 +207,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod, 1)
# compose file provides x-podman in_pod=true
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self) -> None:
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true: throws an error
@ -240,7 +240,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_true_command_line_in_pod_true(self) -> None:
def test_x_podman_in_pod_true_command_line_in_pod_true(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true and and command line in_pod=True: throws an error
@ -274,7 +274,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_true_command_line_in_pod_false(self) -> None:
def test_x_podman_in_pod_true_command_line_in_pod_false(self):
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -319,7 +319,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self) -> None:
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true and command line in_pod="": throws an error
@ -354,7 +354,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod)
# compose file does not provide x-podman in_pod
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self) -> None:
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error
@ -387,7 +387,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self) -> None:
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true: throws an error
@ -421,7 +421,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self) -> None:
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self):
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -467,136 +467,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_docker_compat(self) -> None:
"""
Test that podman-compose will not create a pod when docker compat is requested.
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"up",
"-d",
]
down_cmd = [
"python3",
podman_compose_path(),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"down",
]
env = {
"PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT": "1",
}
try:
self.run_subprocess_assert_returncode(
command_up, failure_exitcode_when_rootful(), env=env
)
finally:
self.run_subprocess_assert_returncode(down_cmd, env=env)
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_env_var(self) -> None:
"""
Test that podman-compose will not create a pod when env var is set.
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"up",
"-d",
]
down_cmd = [
"python3",
podman_compose_path(),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"down",
]
env = {
"PODMAN_COMPOSE_IN_POD": "0",
}
try:
self.run_subprocess_assert_returncode(
command_up, failure_exitcode_when_rootful(), env=env
)
finally:
self.run_subprocess_assert_returncode(down_cmd, env=env)
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_custom_name(self) -> None:
"""
Test that podman-compose will create a pod with a custom name
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_custom_name",
"docker-compose.yml",
),
"up",
"--no-start",
]
try:
self.run_subprocess_assert_returncode(command_up)
finally:
command_rm_pod = ["podman", "pod", "rm", "custom_test_pod_name"]
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self) -> None:
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self):
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error

View File

@ -7,7 +7,7 @@ from tests.integration.test_utils import RunSubprocessMixin
class TestPodmanComposeInclude(unittest.TestCase, RunSubprocessMixin):
def test_podman_compose_include(self) -> None:
def test_podman_compose_include(self):
"""
Test that podman-compose can execute podman-compose -f <file> up with include
:return:

View File

@ -1,2 +1 @@
DOT_ENV_VARIABLE=This value is from the .env file
TEST_LABELS=TEST

View File

@ -11,10 +11,4 @@ services:
EXAMPLE_DOT_ENV: $DOT_ENV_VARIABLE
EXAMPLE_LITERAL: This is a $$literal
EXAMPLE_EMPTY: $NOT_A_VARIABLE
labels_test:
image: busybox
labels:
- "$TEST_LABELS=test_labels"
- test.${TEST_LABELS}=${TEST_LABELS}
- "${TEST_LABELS}.test2=test2(`${TEST_LABELS}`)"

View File

@ -1,6 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
import json
import os
import unittest
@ -9,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "interpolation"), "docker-compose.yml")
class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin):
def test_interpolation(self) -> None:
def test_interpolation(self):
try:
self.run_subprocess_assert_returncode([
"env",
@ -37,18 +36,6 @@ class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin):
self.assertIn("EXAMPLE_DOT_ENV='This value is from the .env file'", str(output))
self.assertIn("EXAMPLE_EMPTY=''", str(output))
self.assertIn("EXAMPLE_LITERAL='This is a $literal'", str(output))
output, _ = self.run_subprocess_assert_returncode([
"podman",
"inspect",
"interpolation_labels_test_1",
])
inspect_output = json.loads(output)
labels_dict = inspect_output[0].get("Config", {}).get("Labels", {})
self.assertIn(('TEST', 'test_labels'), labels_dict.items())
self.assertIn(('TEST.test2', 'test2(`TEST`)'), labels_dict.items())
self.assertIn(('test.TEST', 'TEST'), labels_dict.items())
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "ipam_default"), "docker-compose.yaml")
class TestComposeIpamDefault(unittest.TestCase, RunSubprocessMixin):
def test_ipam_default(self) -> None:
def test_ipam_default(self):
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"],

View File

@ -2,7 +2,6 @@
import os
import time
import unittest
from parameterized import parameterized
@ -13,7 +12,7 @@ from tests.integration.test_utils import test_path
class TestLifetime(unittest.TestCase, RunSubprocessMixin):
def test_up_single_container(self) -> None:
def test_up_single_container(self):
"""Podman compose up should be able to start containers one after another"""
compose_path = os.path.join(test_path(), "lifetime/up_single_container/docker-compose.yml")
@ -69,7 +68,7 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
("no_ports", "up_single_container_many_times"),
("with_ports", "up_single_container_many_times_with_ports"),
])
def test_up_single_container_many_times(self, name: str, subdir: str) -> None:
def test_up_single_container_many_times(self, name, subdir):
"""Podman compose up should be able to start a container many times after it finishes
running.
"""
@ -86,14 +85,15 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
"container1",
])
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_path,
"up",
"-d",
"container2",
])
for _ in range(0, 3):
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_path,
"up",
"-d",
"container2",
])
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -105,7 +105,6 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
self.assertEqual(out, b"test1\n")
# "restart: always" keeps restarting container until its removal
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
@ -114,22 +113,13 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
"container2",
])
if not out.startswith(b"test2\ntest2"):
time.sleep(1)
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_path,
"logs",
"container2",
])
self.assertTrue(out.startswith(b"test2\ntest2"))
# BUG: container should be started 3 times, not 4.
self.assertEqual(out, b"test2\n" * 4)
finally:
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_path,
"down",
"-t",
"0",
])

View File

@ -5,5 +5,5 @@ services:
command: ["/bin/bash", "-c", "echo test1; sleep infinity"]
container2:
image: nopush/podman-compose-test
restart: always
restart: never
command: ["/bin/bash", "-c", "echo test2"]

View File

@ -6,6 +6,6 @@ services:
command: ["/bin/bash", "-c", "echo test1; sleep infinity"]
container2:
image: nopush/podman-compose-test
restart: always
restart: never
ports: "9002:9002"
command: ["/bin/bash", "-c", "echo test2"]

View File

@ -1 +0,0 @@

View File

@ -9,19 +9,16 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_attribute/docker-compose.yaml",
)
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "override_tag_attribute"), "docker-compose.yaml")
class TestComposeOverrideTagAttribute(unittest.TestCase, RunSubprocessMixin):
# test if a service attribute from docker-compose.yaml file is overridden
def test_override_tag_attribute(self) -> None:
def test_override_tag_attribute(self):
override_file = os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_attribute/docker-compose.override_attribute.yaml",
os.path.join(test_path(), "override_tag_attribute"),
"docker-compose.override_attribute.yaml",
)
try:
self.run_subprocess_assert_returncode([

View File

@ -9,19 +9,16 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_service/docker-compose.yaml",
)
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "override_tag_service"), "docker-compose.yaml")
class TestComposeOverrideTagService(unittest.TestCase, RunSubprocessMixin):
# test if whole service from docker-compose.yaml file is overridden in another file
def test_override_tag_service(self) -> None:
def test_override_tag_service(self):
override_file = os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_service/docker-compose.override_service.yaml",
os.path.join(test_path(), "override_tag_service"),
"docker-compose.override_service.yaml",
)
try:
self.run_subprocess_assert_returncode([

View File

@ -3,4 +3,3 @@ services:
app:
image: busybox
command: !reset {}
depends_on: !reset null

View File

@ -3,5 +3,3 @@ services:
app:
image: busybox
command: ["/bin/busybox", "echo", "Zero"]
depends_on:
- db

View File

@ -8,19 +8,15 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(
test_path(),
"merge/reset_and_override_tags/reset_tag_attribute/docker-compose.yaml",
)
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "reset_tag_attribute"), "docker-compose.yaml")
class TestComposeResetTagAttribute(unittest.TestCase, RunSubprocessMixin):
# test if the attribute of the service is correctly reset
def test_reset_tag_attribute(self) -> None:
def test_reset_tag_attribute(self):
reset_file = os.path.join(
test_path(),
"merge/reset_and_override_tags/reset_tag_attribute/docker-compose.reset_attribute.yaml",
os.path.join(test_path(), "reset_tag_attribute"), "docker-compose.reset_attribute.yaml"
)
try:
self.run_subprocess_assert_returncode([
@ -53,8 +49,6 @@ class TestComposeResetTagAttribute(unittest.TestCase, RunSubprocessMixin):
"logs",
])
self.assertEqual(output, b"")
# depends_on: !reset null testing: if this test works, depends_on is correctly reset.
# Otherwise the test would break, since "db" dependency service is not provided
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),

View File

@ -8,18 +8,15 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(
test_path(), "merge/reset_and_override_tags/reset_tag_service/docker-compose.yaml"
)
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "reset_tag_service"), "docker-compose.yaml")
class TestComposeResetTagService(unittest.TestCase, RunSubprocessMixin):
# test if whole service from docker-compose.yaml file is reset
def test_reset_tag_service(self) -> None:
def test_reset_tag_service(self):
reset_file = os.path.join(
test_path(),
"merge/reset_and_override_tags/reset_tag_service/docker-compose.reset_service.yaml",
os.path.join(test_path(), "reset_tag_service"), "docker-compose.reset_service.yaml"
)
try:
self.run_subprocess_assert_returncode([

View File

@ -9,14 +9,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(compose_name: str) -> str:
def compose_yaml_path(compose_name):
""" "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "merge/volumes_merge/")
base_path = os.path.join(test_path(), "volumes_merge/")
return os.path.join(base_path, compose_name)
class TestComposeVolumesMerge(unittest.TestCase, RunSubprocessMixin):
def test_volumes_merge(self) -> None:
def test_volumes_merge(self):
# test if additional compose file overrides host path and access mode of a volume
try:
self.run_subprocess_assert_returncode([
@ -55,7 +55,7 @@ class TestComposeVolumesMerge(unittest.TestCase, RunSubprocessMixin):
binds_info = volumes_info["HostConfig"]["Binds"]
binds_info.sort()
file_path = os.path.join(test_path(), "merge/volumes_merge/override.txt")
file_path = os.path.join(test_path(), "volumes_merge/override.txt")
expected = [
f'{file_path}:/var/www/html/index.html:ro,rprivate,rbind',
f'{file_path}:/var/www/html/index2.html:rw,rprivate,rbind',

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "multicompose"), "docker-compose.yml")
class TestComposeMulticompose(unittest.TestCase, RunSubprocessMixin):
def test_multicompose(self) -> None:
def test_multicompose(self):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -1,7 +0,0 @@
services:
web:
image: busybox
command: httpd -f -p 8123 -h /tmp/
x-podman:
name_separator_compat: true

View File

@ -1,4 +0,0 @@
services:
web:
image: busybox
command: httpd -f -p 8123 -h /tmp/

View File

@ -1,60 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from parameterized import parameterized
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
class TestComposeNameSeparatorCompat(unittest.TestCase, RunSubprocessMixin):
@parameterized.expand([
('default', {}, '_'),
('default', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1'}, '-'),
('default', {'PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT': '1'}, '-'),
('compat', {}, '-'),
('compat', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1'}, '-'),
('compat', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '0'}, '_'),
])
def test_container_name(self, file: str, env: dict[str, str], expected_sep: str) -> None:
compose_yaml_path = os.path.join(
test_path(), "name_separator_compat", f"docker-compose_{file}.yaml"
)
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path, "up", "-d"],
env=env,
)
container_name_out, _ = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path,
"ps",
"--format",
'{{.Names}}',
],
env=env,
)
container_name = container_name_out.decode('utf-8').strip()
expected_container_name = f'name_separator_compat{expected_sep}web{expected_sep}1'
self.assertEqual(container_name, expected_container_name)
finally:
self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path,
"down",
"-t",
"0",
],
env=env,
)

View File

@ -10,20 +10,20 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "nethost"), "docker-compose.yaml")
class TestComposeNethost(unittest.TestCase, RunSubprocessMixin):
# check if container listens for http requests and sends response back
# as network_mode: host allows to connect to container easily
def test_nethost(self) -> None:
def test_nethost(self):
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"],
)
container_id_out, _ = self.run_subprocess_assert_returncode(
container_id, _ = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
@ -33,7 +33,7 @@ class TestComposeNethost(unittest.TestCase, RunSubprocessMixin):
'{{.ID}}',
],
)
container_id = container_id_out.decode('utf-8').split('\n')[0]
container_id = container_id.decode('utf-8').split('\n')[0]
output, _ = self.run_subprocess_assert_returncode(
[
"podman",

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "nets_test1"), "docker-compose.yml")
class TestComposeNetsTest1(unittest.TestCase, RunSubprocessMixin):
# test if port mapping works as expected
def test_nets_test1(self) -> None:
def test_nets_test1(self):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "nets_test2"), "docker-compose.yml")
class TestComposeNetsTest2(unittest.TestCase, RunSubprocessMixin):
# test if port mapping works as expected with networks top-level element
def test_nets_test2(self) -> None:
def test_nets_test2(self):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "nets_test3"), "docker-compose.yml")
@ -28,12 +28,8 @@ class TestComposeNetsTest3(unittest.TestCase, RunSubprocessMixin):
("nets_test3_web1_1", "alias21", b"", 1),
])
def test_nets_test3(
self,
container_name: str,
nework_alias_name: str,
expected_text: bytes,
expected_returncode: int,
) -> None:
self, container_name, nework_alias_name, expected_text, expected_returncode
):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -8,14 +8,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "nets_test_ip"), "docker-compose.yml")
class TestComposeNetsTestIp(unittest.TestCase, RunSubprocessMixin):
# test if services retain custom ipv4_address and mac_address matching the subnet provided
# in networks top-level element
def test_nets_test_ip(self) -> None:
def test_nets_test_ip(self):
try:
self.run_subprocess_assert_returncode(
[

View File

@ -9,7 +9,6 @@ Tests the podman networking parameters
# pylint: disable=redefined-outer-name
import os
import unittest
from typing import Generator
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
@ -18,11 +17,11 @@ from tests.integration.test_utils import test_path
class TestPodmanComposeNetwork(RunSubprocessMixin, unittest.TestCase):
@staticmethod
def compose_file() -> str:
def compose_file():
"""Returns the path to the compose file used for this test module"""
return os.path.join(test_path(), "nets_test_ip", "docker-compose.yml")
def teardown(self) -> Generator[None, None, None]:
def teardown(self):
"""
Ensures that the services within the "profile compose file" are removed between
each test case.
@ -41,7 +40,7 @@ class TestPodmanComposeNetwork(RunSubprocessMixin, unittest.TestCase):
]
self.run_subprocess(down_cmd)
def test_networks(self) -> None:
def test_networks(self):
up_cmd = [
"coverage",
"run",
@ -116,7 +115,7 @@ class TestPodmanComposeNetwork(RunSubprocessMixin, unittest.TestCase):
self.assertIn(f"ether {mac}", out.decode('utf-8'))
self.assertIn(f"inet {ip}/", out.decode('utf-8'))
def test_down_with_network(self) -> None:
def test_down_with_network(self):
try:
self.run_subprocess_assert_returncode([
"coverage",

View File

@ -10,10 +10,10 @@ from tests.integration.test_utils import test_path
class TestPodmanComposeNetworkInterfaceName(RunSubprocessMixin, unittest.TestCase):
def compose_file(self) -> str:
def compose_file(self):
return os.path.join(test_path(), "network_interface_name", "docker-compose.yml")
def up(self) -> None:
def up(self):
up_cmd = [
"coverage",
"run",
@ -26,7 +26,7 @@ class TestPodmanComposeNetworkInterfaceName(RunSubprocessMixin, unittest.TestCas
]
self.run_subprocess_assert_returncode(up_cmd)
def down(self) -> None:
def down(self):
down_cmd = [
"coverage",
"run",
@ -38,7 +38,7 @@ class TestPodmanComposeNetworkInterfaceName(RunSubprocessMixin, unittest.TestCas
]
self.run_subprocess(down_cmd)
def test_interface_name(self) -> None:
def test_interface_name(self):
try:
self.up()

View File

@ -11,18 +11,18 @@ from tests.integration.test_utils import test_path
class TestPodmanComposeNetworkScopedAliases(RunSubprocessMixin, unittest.TestCase):
@staticmethod
def compose_file() -> str:
def compose_file():
"""Returns the path to the compose file used for this test module"""
return os.path.join(test_path(), "network_scoped_aliases", "docker-compose.yaml")
def test_network_scoped_aliases(self) -> None:
def test_network_scoped_aliases(self):
try:
self.up()
self.verify()
finally:
self.down()
def up(self) -> None:
def up(self):
up_cmd = [
"coverage",
"run",
@ -36,7 +36,7 @@ class TestPodmanComposeNetworkScopedAliases(RunSubprocessMixin, unittest.TestCas
self.run_subprocess_assert_returncode(up_cmd)
def down(self) -> None:
def down(self):
down_cmd = [
"coverage",
"run",
@ -48,7 +48,7 @@ class TestPodmanComposeNetworkScopedAliases(RunSubprocessMixin, unittest.TestCas
]
self.run_subprocess(down_cmd)
def verify(self) -> None:
def verify(self):
expected_results = [
("utils-net0", "web1", ["172.19.3.11"]),
("utils-net0", "secure-web", ["172.19.3.11"]),
@ -72,7 +72,7 @@ class TestPodmanComposeNetworkScopedAliases(RunSubprocessMixin, unittest.TestCas
addresses = self.parse_dnslookup(out.decode())
self.assertEqual(addresses, expected_result)
def parse_dnslookup(self, output: str) -> list[str]:
def parse_dnslookup(self, output):
lines = output.splitlines()
addresses = []
for line in lines:

View File

@ -8,13 +8,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "no_services"), "docker-compose.yaml")
class TestComposeNoServices(unittest.TestCase, RunSubprocessMixin):
# test if a network was created, but not the services
def test_no_services(self) -> None:
def test_no_services(self):
try:
output, return_code = self.run_subprocess_assert_returncode(
[

View File

@ -1,4 +0,0 @@
version: "3"
services:foo
web1:
image: busybox

View File

@ -1,4 +0,0 @@
version: "3"
services:
web1:
image: busybox

View File

@ -1,66 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def bad_compose_yaml_path() -> str:
base_path = os.path.join(test_path(), "parse-error")
return os.path.join(base_path, "docker-compose-error.yml")
def good_compose_yaml_path() -> str:
base_path = os.path.join(test_path(), "parse-error")
return os.path.join(base_path, "docker-compose.yml")
class TestComposeBuildParseError(unittest.TestCase, RunSubprocessMixin):
def test_no_error(self) -> None:
try:
_, err = self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", good_compose_yaml_path(), "config"], 0
)
self.assertEqual(b"", err)
finally:
self.run_subprocess([
podman_compose_path(),
"-f",
bad_compose_yaml_path(),
"down",
])
def test_simple_parse_error(self) -> None:
try:
_, err = self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", bad_compose_yaml_path(), "config"], 1
)
self.assertIn(b"could not find expected ':'", err)
self.assertNotIn(b"\nTraceback (most recent call last):\n", err)
finally:
self.run_subprocess([
podman_compose_path(),
"-f",
bad_compose_yaml_path(),
"down",
])
def test_verbose_parse_error_contains_stack_trace(self) -> None:
try:
_, err = self.run_subprocess_assert_returncode(
[podman_compose_path(), "--verbose", "-f", bad_compose_yaml_path(), "config"], 1
)
self.assertIn(b"\nTraceback (most recent call last):\n", err)
finally:
self.run_subprocess([
podman_compose_path(),
"-f",
bad_compose_yaml_path(),
"down",
])

View File

@ -7,23 +7,23 @@ import unittest
from tests.integration.test_utils import RunSubprocessMixin
def base_path() -> str:
def base_path():
"""Returns the base path for the project"""
return os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
def test_path() -> str:
def test_path():
"""Returns the path to the tests directory"""
return os.path.join(base_path(), "tests/integration")
def podman_compose_path() -> str:
def podman_compose_path():
"""Returns the path to the podman compose script"""
return os.path.join(base_path(), "podman_compose.py")
class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
def load_pod_info(self, pod_name: str) -> dict:
def load_pod_info(self, pod_name):
output, _ = self.run_subprocess_assert_returncode([
"podman",
"pod",
@ -37,7 +37,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
return pod_info[0]
return pod_info
def run_pod_args_test(self, config: str, args: list, expected: list) -> None:
def run_pod_args_test(self, config, args, expected):
"""
Helper to run podman up with a docker-compose.yml config, additional
(--pod-args) arguments and compare the CreateCommand of the resulting
@ -78,7 +78,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
command_rm_pod = ["podman", "pod", "rm", pod_name]
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_pod_args_unset_unset(self) -> None:
def test_x_podman_pod_args_unset_unset(self):
"""
Test that podman-compose will use the default pod-args when unset in
both docker-compose.yml and command line
@ -89,7 +89,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
["--infra=false", "--share="],
)
def test_x_podman_pod_args_unset_empty(self) -> None:
def test_x_podman_pod_args_unset_empty(self):
"""
Test that podman-compose will use empty pod-args when unset in
docker-compose.yml and passing an empty value on the command line
@ -100,7 +100,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
[],
)
def test_x_podman_pod_args_unset_set(self) -> None:
def test_x_podman_pod_args_unset_set(self):
"""
Test that podman-compose will use the passed pod-args when unset in
docker-compose.yml and passing a non-empty value on the command line
@ -111,7 +111,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
["--infra=false", "--share=", "--cpus=1"],
)
def test_x_podman_pod_args_empty_unset(self) -> None:
def test_x_podman_pod_args_empty_unset(self):
"""
Test that podman-compose will use empty pod-args when set to an
empty value in docker-compose.yml and unset on the command line
@ -122,7 +122,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
[],
)
def test_x_podman_pod_args_empty_empty(self) -> None:
def test_x_podman_pod_args_empty_empty(self):
"""
Test that podman-compose will use empty pod-args when set to an
empty value in both docker-compose.yml and command line
@ -133,7 +133,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
[],
)
def test_x_podman_pod_args_empty_set(self) -> None:
def test_x_podman_pod_args_empty_set(self):
"""
Test that podman-compose will use the passed pod-args when set to an
empty value in docker-compose.yml and passing a non-empty value on the
@ -145,7 +145,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
["--infra=false", "--share=", "--cpus=1"],
)
def test_x_podman_pod_args_set_unset(self) -> None:
def test_x_podman_pod_args_set_unset(self):
"""
Test that podman-compose will use the set pod-args when set to a
non-empty value in docker-compose.yml and unset on the command line
@ -156,7 +156,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
["--infra=false", "--share=", "--cpus=2"],
)
def test_x_podman_pod_args_set_empty(self) -> None:
def test_x_podman_pod_args_set_empty(self):
"""
Test that podman-compose will use empty pod-args when set to a
non-empty value in docker-compose.yml and passing an empty value on
@ -168,7 +168,7 @@ class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin):
[],
)
def test_x_podman_pod_args_set_set(self) -> None:
def test_x_podman_pod_args_set_set(self):
"""
Test that podman-compose will use the passed pod-args when set to a
non-empty value in both docker-compose.yml and command line

Some files were not shown because too many files have changed in this diff Show More