diff --git a/poetry.lock b/poetry.lock index 56cdb7b..0c9da25 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "adcm-version" @@ -6,6 +6,7 @@ version = "1.0.3" description = "" optional = false python-versions = ">=3.8,<4.0" +groups = ["main"] files = [ {file = "adcm_version-1.0.3-py3-none-any.whl", hash = "sha256:e59bc0e6ed23ee0bc870a5a6b5c1a6ea7c671914e43c2cee6a5fb0d1e3c314ab"}, {file = "adcm_version-1.0.3.tar.gz", hash = "sha256:2052d7c17ef72f1e32971e939ec972426978025e5c052320062f4ed3a2c90bc5"}, @@ -20,6 +21,7 @@ version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, @@ -40,6 +42,7 @@ version = "3.13.0" description = "The missing async toolbox" optional = false python-versions = "~=3.8" +groups = ["main"] files = [ {file = "asyncstdlib-3.13.0-py3-none-any.whl", hash = "sha256:60e097c19e815f3c419a77426cf6c3653aebcb766544d631d5ce6128d0851ae8"}, {file = "asyncstdlib-3.13.0.tar.gz", hash = "sha256:f2a6ffb44f118233bb99bef50861d6f64c432decbdcc4c2cb93b3fff40d1b533"}, @@ -56,6 +59,7 @@ version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "test"] files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, @@ -67,6 +71,7 @@ version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["test"] files = [ {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, @@ -181,6 +186,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["test"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -192,6 +199,7 @@ version = "7.1.0" description = "A Python library for the Docker Engine API." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, @@ -208,12 +216,28 @@ docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] ssh = ["paramiko (>=2.4.3)"] websockets = ["websocket-client (>=1.3.0)"] +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +groups = ["test"] +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -225,6 +249,7 @@ version = "1.0.6" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, @@ -246,6 +271,7 @@ version = "0.27.2" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, @@ -271,6 +297,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main", "test"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -285,6 +312,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -296,6 +324,7 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -307,6 +336,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -318,6 +348,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -333,6 +364,7 @@ version = "1.1.388" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pyright-1.1.388-py3-none-any.whl", hash = "sha256:c7068e9f2c23539c6ac35fc9efac6c6c1b9aa5a0ce97a9a8a6cf0090d7cbf84c"}, {file = "pyright-1.1.388.tar.gz", hash = "sha256:0166d19b716b77fd2d9055de29f71d844874dbc6b9d3472ccd22df91db3dfa34"}, @@ -353,6 +385,7 @@ version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, @@ -373,6 +406,7 @@ version = "0.24.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"}, {file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"}, @@ -391,6 +425,7 @@ version = "2.3.1" description = "pytest plugin to abort hanging tests" optional = false python-versions = ">=3.7" +groups = ["test"] files = [ {file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"}, {file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"}, @@ -399,12 +434,35 @@ files = [ [package.dependencies] pytest = ">=7.0.0" +[[package]] +name = "pytest-xdist" +version = "3.6.1" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.8" +groups = ["test"] +files = [ + {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, + {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "pywin32" version = "308" description = "Python for Window Extensions" optional = false python-versions = "*" +groups = ["test"] +markers = "sys_platform == \"win32\"" files = [ {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, @@ -432,6 +490,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -494,6 +553,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -515,6 +575,7 @@ version = "0.7.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344"}, {file = "ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0"}, @@ -542,6 +603,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -553,6 +615,7 @@ version = "4.8.2" description = "Python library for throwaway instances of anything that can run in a Docker container" optional = false python-versions = "<4.0,>=3.9" +groups = ["test"] files = [ {file = "testcontainers-4.8.2-py3-none-any.whl", hash = "sha256:9e19af077cd96e1957c13ee466f1f32905bc6c5bc1bc98643eb18be1a989bfb0"}, {file = "testcontainers-4.8.2.tar.gz", hash = "sha256:dd4a6a2ea09e3c3ecd39e180b6548105929d0bb78d665ce9919cb3f8c98f9853"}, @@ -605,6 +668,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["dev", "test"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -616,6 +680,7 @@ version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, @@ -633,6 +698,7 @@ version = "0.3.2" description = "Library for parsing system package strings and comparing package versions" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "version_utils-0.3.2-py2.py3-none-any.whl", hash = "sha256:4e0f3dff669d7a081dd66d8b616752dc309e7246a7b2c5ac800dde5ec0d9a555"}, {file = "version_utils-0.3.2.tar.gz", hash = "sha256:308191f111395ac19ec5ef4650764af29962a6415d8391785027ae5328579299"}, @@ -644,6 +710,7 @@ version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" +groups = ["test"] files = [ {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, @@ -713,6 +780,6 @@ files = [ ] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.12" -content-hash = "12ba90548634f9b239e20ca9b937dc8dd3fee507a274586c4afcebfcc6b3461d" +content-hash = "92cd0c3cce3516b41630fd81717e772b4cbf51a4de6709ce454cc4d654320ba0" diff --git a/pyproject.toml b/pyproject.toml index 6763888..48c456b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ testcontainers = "^4.8.2" pyyaml = "^6.0.2" pytest-timeout = "^2.3.1" docker = "^7.1.0" +pytest-xdist = "^3.6.1" [build-system] requires = ["poetry-core"] diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 809d1e5..ed49958 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,7 +1,6 @@ from collections.abc import AsyncGenerator, Generator from io import BytesIO from pathlib import Path -from time import sleep from urllib.parse import urljoin import os import random @@ -10,7 +9,6 @@ from httpx import AsyncClient from testcontainers.core.network import Network -import httpx import pytest import pytest_asyncio @@ -34,35 +32,6 @@ ################ -def load_certs_to_running_adcm(adcm: ADCMContainer, certs_dir: Path) -> None: - file = BytesIO() - with tarfile.open(mode="w:gz", fileobj=file) as tar: - tar.add(certs_dir, "") - file.seek(0) - - container = adcm.get_wrapped_container() - container.put_archive("/adcm/data/conf/ssl", file.read()) - ec, out = adcm.exec(["nginx", "-s", "reload"]) - if ec != 0: - raise RuntimeError(f"Failed to reload nginx after attaching certs: {out.decode('utf-8')}") - - verify_cert_path = str(certs_dir / "cert.pem") - - attempts = 15 - last_err = None - - for _ in range(attempts): - try: - httpx.get(adcm.ssl_url, verify=verify_cert_path) - except httpx.ConnectError as e: - last_err = e - sleep(0.1) - else: - return - - raise RuntimeError(f"Failed to connect to HTTPS port with {attempts} attempts") from last_err - - @pytest.fixture(scope="session") def network() -> Generator[Network, None, None]: with Network() as network: @@ -102,12 +71,13 @@ def adcm_image(network: Network, postgres: ADCMPostgresContainer, ssl_certs_dir: db = DatabaseInfo(name=f"adcm_{suffix}_migration", host=postgres.name) postgres.execute_statement(f"CREATE DATABASE {db.name} OWNER {DB_USER}") - with ADCMContainer(image=f"{base_repo}:{base_tag}", network=network, db=db, migration_mode=True) as adcm: - file = BytesIO() - with tarfile.open(mode="w:gz", fileobj=file) as tar: - tar.add(ssl_certs_dir, "") - file.seek(0) + file = BytesIO() + with tarfile.open(mode="w:gz", fileobj=file) as tar: + tar.add(ssl_certs_dir, "") + file.seek(0) + adcm = ADCMContainer(image=f"{base_repo}:{base_tag}", network=network, db=db, migration_mode=True) + with adcm: container = adcm.get_wrapped_container() container.put_archive("/adcm/data/conf/ssl", file.read()) container.commit(repository=new_repo, tag=new_tag) @@ -121,7 +91,9 @@ def adcm(network: Network, postgres: ADCMPostgresContainer, adcm_image: str) -> db = DatabaseInfo(name=f"adcm_{suffix}", host=postgres.name) postgres.execute_statement(f"CREATE DATABASE {db.name} OWNER {DB_USER}") - with ADCMContainer(image=adcm_image, network=network, db=db) as container: + adcm = ADCMContainer(image=adcm_image, network=network, db=db) + + with adcm as container: yield container postgres.execute_statement(f"DROP DATABASE {db.name}") diff --git a/tests/integration/setup_environment.py b/tests/integration/setup_environment.py index 24a3d81..3bb1e18 100644 --- a/tests/integration/setup_environment.py +++ b/tests/integration/setup_environment.py @@ -1,12 +1,16 @@ from dataclasses import dataclass +from time import sleep from typing import Self +import random import socket +import string from docker.errors import DockerException from testcontainers.core.container import DockerContainer from testcontainers.core.network import Network from testcontainers.core.waiting_utils import wait_container_is_ready, wait_for_logs from testcontainers.postgres import DbContainer, PostgresContainer +import docker.errors postgres_image_name = "postgres:latest" adcm_image_name = "hub.adsw.io/adcm/adcm:develop" @@ -38,7 +42,8 @@ def find_free_port(start: int, end: int) -> int: class ADCMPostgresContainer(PostgresContainer): def __init__(self: Self, image: str, network: Network) -> None: super().__init__(image) - self.name = postgres_name + suffix = "".join(random.sample(string.ascii_letters, k=6)).lower() + self.name = f"test_pg_db_{suffix}" self.with_name(self.name) self.with_network(network) @@ -80,14 +85,26 @@ def __init__(self: Self, image: str, network: Network, db: DatabaseInfo, *, migr self.with_env("DB_PORT", str(self._db.port)) def start(self: Self) -> Self: - adcm_port = find_free_port(start=8000, end=8080) - self.with_bind_ports(8000, adcm_port) - ssl_port = find_free_port(start=8400, end=8480) - self.with_bind_ports(8443, ssl_port) - - self.with_name(f"{adcm_container_name}_{adcm_port}") - - super().start() + last_err = None + for _ in range(20): + suffix = "".join(random.sample(string.ascii_letters, k=6)).lower() + self.with_name(f"{adcm_container_name}_{suffix}") + self.with_bind_ports(8000, find_free_port(start=8000, end=8080)) + self.with_bind_ports(8443, find_free_port(start=8400, end=8480)) + + try: + super().start() + except docker.errors.APIError as e: + last_err = e + sleep(0.05) + else: + break + else: + if last_err: + raise last_err + + message = "ADCM start loop hasn't invoke `break` and has error, container state is unpredictable" + raise RuntimeError(message) wait_container_is_ready(self) ready_logs = "Run Nginx ..." if not self._migration_mode else "Run main wsgi application ..." @@ -95,6 +112,7 @@ def start(self: Self) -> Self: ip = self.get_container_host_ip() port = self.get_exposed_port(8000) + ssl_port = self.get_exposed_port(8443) self.url = f"http://{ip}:{port}" self.ssl_url = f"https://{ip}:{ssl_port}"