Skip to content

chore: Update pyproject and tests to support Mac's/arm local development #814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ jobs:
run: poetry install --all-extras
- name: Run twine check
run: poetry build && poetry run twine check dist/*.tar.gz
- name: Display Docker and Compose Versions
run: |
@echo "##[group]Docker Version"
@docker --version || echo "Docker is not installed or misconfigured"
@echo "##[endgroup]"
@echo "##[group]Docker Compose Version"
@docker compose version || docker-compose --version || echo "Docker Compose is not installed or misconfigured"
@echo "##[endgroup]"
Comment on lines +28 to +35
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this to workflow command to help with debugging docker errors in the checks.

- name: Run tests
run: make core/tests
- name: Rename coverage file
Expand Down
9 changes: 9 additions & 0 deletions core/tests/test_core_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
from testcontainers.core.waiting_utils import wait_container_is_ready

from testcontainers.registry import DockerRegistryContainer
from testcontainers.core.utils import is_mac


@pytest.mark.skipif(
is_mac(),
reason="Docker Desktop on macOS does not support insecure private registries without daemon reconfiguration",
)
def test_missing_on_private_registry(monkeypatch):
username = "user"
password = "pass"
Expand All @@ -41,6 +46,10 @@ def test_missing_on_private_registry(monkeypatch):
wait_container_is_ready(test_container)


@pytest.mark.skipif(
is_mac(),
reason="Docker Desktop on macOS does not support local insecure registries over HTTP without modifying daemon settings",
)
@pytest.mark.parametrize(
"image,tag,username,password",
[
Expand Down
8 changes: 8 additions & 0 deletions core/tests/test_docker_in_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from testcontainers.core.container import DockerContainer
from testcontainers.core.docker_client import DockerClient, LOGGER
from testcontainers.core.utils import inside_container
from testcontainers.core.utils import is_mac
from testcontainers.core.waiting_utils import wait_for_logs


Expand All @@ -36,6 +37,7 @@ def _wait_for_dind_return_ip(client, dind):
return docker_host_ip


@pytest.mark.skipif(is_mac(), reason="Docker socket forwarding (socat) is unsupported on Docker Desktop for macOS")
def test_wait_for_logs_docker_in_docker():
# real dind isn't possible (AFAIK) in CI
# forwarding the socket to a container port is at least somewhat the same
Expand Down Expand Up @@ -64,6 +66,9 @@ def test_wait_for_logs_docker_in_docker():
not_really_dind.remove()


@pytest.mark.skipif(
is_mac(), reason="Bridge networking and Docker socket forwarding are not supported on Docker Desktop for macOS"
)
def test_dind_inherits_network():
client = DockerClient()
try:
Expand Down Expand Up @@ -158,6 +163,9 @@ def test_find_host_network_in_dood() -> None:
assert DockerClient().find_host_network() == os.environ[EXPECTED_NETWORK_VAR]


@pytest.mark.skipif(
is_mac(), reason="Docker socket mounting and container networking do not work reliably on Docker Desktop for macOS"
)
@pytest.mark.skipif(not Path(tcc.ryuk_docker_socket).exists(), reason="No docker socket available")
def test_dood(python_testcontainer_image: str) -> None:
"""
Expand Down
8 changes: 8 additions & 0 deletions core/tests/test_ryuk.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
from testcontainers.core.config import testcontainers_config
from testcontainers.core.container import Reaper
from testcontainers.core.container import DockerContainer
from testcontainers.core.utils import is_mac
from testcontainers.core.waiting_utils import wait_for_logs


@pytest.mark.skipif(
is_mac(),
reason="Ryuk container reaping is unreliable on Docker Desktop for macOS due to VM-based container lifecycle handling",
)
@pytest.mark.inside_docker_check
def test_wait_for_reaper(monkeypatch: MonkeyPatch):
Reaper.delete_instance()
Expand Down Expand Up @@ -41,6 +46,9 @@ def test_wait_for_reaper(monkeypatch: MonkeyPatch):
Reaper.delete_instance()


@pytest.mark.skipif(
is_mac(), reason="Ryuk disabling behavior is unreliable on Docker Desktop for macOS due to Docker socket emulation"
)
@pytest.mark.inside_docker_check
def test_container_without_ryuk(monkeypatch: MonkeyPatch):
Reaper.delete_instance()
Expand Down
1 change: 0 additions & 1 deletion core/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def test_is_windows(monkeypatch: MonkeyPatch) -> None:


def test_is_arm(monkeypatch: MonkeyPatch) -> None:
assert not utils.is_arm()
monkeypatch.setattr("platform.machine", lambda: "arm64")
assert utils.is_arm()
monkeypatch.setattr("platform.machine", lambda: "aarch64")
Expand Down
3 changes: 3 additions & 0 deletions modules/cosmosdb/tests/test_cosmosdb_emulator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import pytest
from testcontainers.cosmosdb._emulator import CosmosDBEmulatorContainer

from testcontainers.core.utils import is_arm


@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_runs():
with CosmosDBEmulatorContainer(partition_count=1, bind_ports=False) as emulator:
assert emulator.server_certificate_pem is not None
Expand Down
4 changes: 4 additions & 0 deletions modules/cosmosdb/tests/test_cosmosdb_mongodb.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import pytest
from testcontainers.cosmosdb import CosmosDBMongoEndpointContainer

from testcontainers.core.utils import is_arm


@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_requires_a_version():
with pytest.raises(AssertionError, match="A MongoDB version is required"):
CosmosDBMongoEndpointContainer(mongodb_version=None)
Expand All @@ -10,6 +13,7 @@ def test_requires_a_version():
CosmosDBMongoEndpointContainer(mongodb_version="4.0")


@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_runs():
with CosmosDBMongoEndpointContainer(mongodb_version="4.0", partition_count=1, bind_ports=False) as emulator:
assert emulator.env["AZURE_COSMOS_EMULATOR_ENABLE_MONGODB_ENDPOINT"] == "4.0"
Expand Down
3 changes: 3 additions & 0 deletions modules/cosmosdb/tests/test_cosmosdb_nosql.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import pytest
from testcontainers.cosmosdb import CosmosDBNoSQLEndpointContainer

from testcontainers.core.utils import is_arm


@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_runs():
with CosmosDBNoSQLEndpointContainer(partition_count=1, bind_ports=False) as emulator:
assert emulator.get_exposed_port(8081) is not None, "The NoSQL endpoint's port should be exposed"
1 change: 1 addition & 0 deletions modules/db2/tests/test_db2.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def test_docker_run_db2(version: str):
# - sqlserver
# - mongodb
# - db2
@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_quoted_password():
user = "db2inst1"
dbname = "testdb"
Expand Down
2 changes: 2 additions & 0 deletions modules/elasticsearch/tests/test_elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

import pytest

from testcontainers.core.utils import is_arm
from testcontainers.elasticsearch import ElasticSearchContainer


# The versions below should reflect the latest stable releases
@pytest.mark.parametrize("version", ["7.17.18", "8.12.2"])
@pytest.mark.skipif(is_arm(), reason="db2 container not available for ARM")
def test_docker_run_elasticsearch(version):
with ElasticSearchContainer(f"elasticsearch:{version}", mem_limit="3G") as es:
resp = urllib.request.urlopen(es.get_url())
Expand Down
4 changes: 3 additions & 1 deletion modules/google/tests/test_google.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from queue import Queue
from google.cloud.datastore import Entity

import time
from testcontainers.core.waiting_utils import wait_for_logs
from testcontainers.google import PubSubContainer, DatastoreContainer

Expand All @@ -25,7 +26,8 @@ def test_pubsub_container():
# Receive the message
queue = Queue()
subscriber.subscribe(subscription_path, queue.put)
message = queue.get(timeout=1)
# timeout 10 is needed to account for slower arm machines
message = queue.get(timeout=10)
assert message.data == b"Hello world!"
message.ack()

Expand Down
6 changes: 3 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ httpx = { version = "*", optional = true }
azure-cosmos = { version = "*", optional = true }
cryptography = { version = "*", optional = true }
trino = { version = "*", optional = true }
ibm_db_sa = { version = "*", optional = true }
ibm_db_sa = { version = "*", optional = true, markers = "platform_machine != 'aarch64' and platform_machine != 'arm64'" }

[tool.poetry.extras]
arangodb = ["python-arango"]
Expand Down