testcontainers / testcontainers-python

Testcontainers is a Python library that providing a friendly API to run Docker container. It is designed to create runtime environment to use during your automatic tests.
https://testcontainers-python.readthedocs.io/en/latest/
Apache License 2.0
1.61k stars 296 forks source link

Unexpected Behavior: MySqlContainer `_connect` implementation is flaky #707

Open avaz opened 1 month ago

avaz commented 1 month ago

Describe the bug

The current implementation for MySqlContainer to check if the database is running is like below:

wait_for_logs(
    self,
    re.compile(".*: ready for connections.*: ready for connections.*", flags=re.DOTALL | re.MULTILINE).search,
)

It expects for two pair of "ready for connections" logs to appear in the logs output. This works for vanilla MySQL Docker image but fails for any custom ones, for instance, an image that has a custom database initilization which is something standard and explained how in the official Docker Hub for MySQL section 'Initializing a fresh instance'.

Below is a example of a custom MySQL docker image:

FROM mysql:latest as builder

# Modify the entrypoint to only initialize the database
RUN sed -i 's/exec "\$@"/echo "not running \$@"/' /usr/local/bin/docker-entrypoint.sh

ENV MYSQL_ROOT_PASSWORD=test

# Copy data for initialization and settings
COPY sql/ /docker-entrypoint-initdb.d/
COPY ./bigtext.txt /var/lib/mysql-files/
COPY my.cnf /etc/mysql/my.cnf

# Run the entrypoint script to initialize the database
RUN /usr/local/bin/docker-entrypoint.sh mysqld

FROM mysql:latest

# Copying settings
COPY my.cnf /etc/mysql/my.cnf

# Copy the initialized database from the first stage
COPY --from=builder /var/lib/mysql /var/lib/mysql

# Copy the health table
COPY health-check.sql /health-check.sql

# Override the normal startup to load health-check after database initialization
ENTRYPOINT ["docker-entrypoint.sh", "mysqld", "--init-file", "/health-check.sql"]

And the initialization logs output for this image is like below:

docker run --rm -v ./tmp:/var/lib/mysql -eMYSQL_RANDOM_ROOT_PASSWORD=true sakila-extended-source-db:latest
2024-10-01 17:06:45+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:06:46+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-10-01 17:06:46+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
2024-10-01T17:06:46.171337Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:06:46.312696Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 1
2024-10-01T17:06:46.314299Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:06:46.317485Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:06:46.396872Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:06:46.517414Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:06:46.517454Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:06:46.519802Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:06:46.525651Z 7 [ERROR] [MY-000061] [Server] 1049  Unknown database 'sakila'.
2024-10-01T17:06:46.526937Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:06:46.526956Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

Logs from vanilla mysql:latest image:

docker run --rm -v ./tmp:/var/lib/mysql -eMYSQL_RANDOM_ROOT_PASSWORD=true mysql:latest                              core -> feature/monorepo-cleanup + ? !
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Initializing database files
2024-10-01T17:04:05.565798Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2024-10-01T17:04:05.566683Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 9.0.1) initializing of server in progress as process 81
2024-10-01T17:04:05.568354Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:05.575007Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:05.689247Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:06.519129Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2024-10-01T17:04:08.317899Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Database files initialized
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Starting temporary server
2024-10-01T17:04:08.364408Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:04:08.507157Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 124
2024-10-01T17:04:08.508364Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:08.515275Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:08.594411Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:08.718336Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:04:08.718374Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:04:08.720619Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:04:08.729333Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:04:08.729354Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1'  socket: '/var/run/mysqld/mysqld.sock'  port: 0  MySQL Community Server - GPL.
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Temporary server started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
2024-10-01 17:04:09+00:00 [Note] [Entrypoint]: GENERATED ROOT PASSWORD: uLXlPdWc6VAglkpK99BoRXuNgH8c7z9s

2024-10-01 17:04:09+00:00 [Note] [Entrypoint]: Stopping temporary server
2024-10-01T17:04:09.444930Z 10 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 9.0.1).
2024-10-01T17:04:10.277268Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 9.0.1)  MySQL Community Server - GPL.
2024-10-01T17:04:10.277290Z 0 [System] [MY-015016] [Server] MySQL Server - end.
2024-10-01 17:04:10+00:00 [Note] [Entrypoint]: Temporary server stopped

2024-10-01 17:04:10+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.

2024-10-01T17:04:10.475599Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:04:10.622838Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 1
2024-10-01T17:04:10.623975Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:10.626794Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:10.705627Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:10.831741Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:04:10.831785Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:04:10.834154Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:04:10.842164Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:04:10.842236Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

In the vanilla there are twice the pair "ready for connections" which makes the regular expression match, but it fails for the custom one. Of course, another approach would be to create a custom testcontainers docker image class but actually this isn't a good idea because the logs for MySql can change anytime and as soon as the official image gets updated testcontainers MySql image class may fail to properly check if the container has started or not.

To Reproduce

Create a docker image like the Dockerfile above and use it in test using testcontainers like below

            >>> import sqlalchemy
            >>> from testcontainers.mysql import MySqlContainer

            >>> with MySqlContainer('mysql-custom:latest') as mysql:
            ...     engine = sqlalchemy.create_engine(mysql.get_connection_url())
            ...     with engine.begin() as connection:
            ...         result = connection.execute(sqlalchemy.text("select version()"))
            ...         version, = result.fetchone()

The test will timeout on waiting for the container to start even that it has already started. I monkey patched the implementation on my local project like below and worked well. The approach below is more reliable as it relies on standard Mysql tooling to check if the service is running or not, also it make use of testcontainers builtin constructs where both tends to be more future-proof.

File modules/mysql/testcontainers/mysql/__init__.py


...
# this code overwrite the method `_connect` of class `MySqlContainer` specified in the file above.

    def _connect(self) -> None:
        def check_if_is_running():
            escaped_single_password = self.password.replace("'", "'\"'\"'")
            result = self.exec(
                [
                    "sh",
                    "-c",
                    f"mysql -u {self.username} -p{escaped_single_password} -h {self.get_container_host_ip()} -P {self.port} -e 'SELECT VERSION();'"
                ]
            )
            if result.exit_code != 0:
                raise ConnectionError(f"Failed to connect to MySQL: {result.output}")
        wait_for(check_if_is_running)

I have it running and tested on my project and I would be happy to submit a PR.

Runtime environment

Provide a summary of your runtime environment. Which operating system, python version, and docker version are you using? What is the version of testcontainers-python you are using? You can run the following commands to get the relevant information.

# Get the operating system information (on a unix os).
$ uname -a
Darwin ****** 24.1.0 Darwin Kernel Version 24.1.0: Tue Sep 17 07:49:16 PDT 2024; root:xnu-11215.40.59~38/RELEASE_ARM64_T6030 arm6
# Get the python version.
$ python --version
Python 3.11.9
# Get the docker version and other docker information.
$ docker info
Client:
 Version:    27.2.0
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.16.2-desktop.1
    Path:     /Users/*****/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.29.2-desktop.2
    Path:     /Users/*****/.docker/cli-plugins/docker-compose
  debug: Get a shell into any image or container (Docker Inc.)
    Version:  0.0.34
    Path:     /Users/*****/.docker/cli-plugins/docker-debug
  desktop: Docker Desktop commands (Alpha) (Docker Inc.)
    Version:  v0.0.15
    Path:     /Users/*****/.docker/cli-plugins/docker-desktop
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.2
    Path:     /Users/*****/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.25
    Path:     /Users/*****/.docker/cli-plugins/docker-extension
  feedback: Provide feedback, right in your terminal! (Docker Inc.)
    Version:  v1.0.5
    Path:     /Users/*****/.docker/cli-plugins/docker-feedback
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v1.3.0
    Path:     /Users/*****/.docker/cli-plugins/docker-init
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
    Version:  0.6.0
    Path:     /Users/*****/.docker/cli-plugins/docker-sbom
  scout: Docker Scout (Docker Inc.)
    Version:  v1.13.0
    Path:     /Users/*****/.docker/cli-plugins/docker-scout

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 25
 Server Version: 27.2.0
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 8fc6bcff51318944179630522a095cc9dbf9f353
 runc version: v1.1.13-0-g58aa920
 init version: de40ad0
 Security Options:
  seccomp
   Profile: unconfined
  cgroupns
 Kernel Version: 6.10.4-linuxkit
 Operating System: Docker Desktop
 OSType: linux
 Architecture: aarch64
 CPUs: 12
 Total Memory: 17.3GiB
 Name: docker-desktop
 ID: 98c933e7-9d31-46e1-a51e-eda5f0f7dc99
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Labels:
  com.docker.desktop.address=unix:///Users/*****/Library/Containers/com.docker.docker/Data/docker-cli.sock
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

# Get all python packages.
$ pip freeze
aiohappyeyeballs==2.4.0
aiohttp==3.10.5
aiohttp-cors==0.7.0
aiosignal==1.3.1
alabaster==0.7.16
annotated-types==0.7.0
anytree==2.12.1
appnope==0.1.4
argcomplete==3.5.0
astroid==2.15.8
asttokens==2.4.1
attrs==24.2.0
azure-core==1.30.2
azure-storage-blob==12.22.0
azure-storage-file-datalake==12.16.0
Babel==2.15.0
bandit==1.7.9
bcrypt==4.2.0
blis==0.7.11
boto3==1.34.78
botocore==1.34.156
cachetools==5.4.0
catalogue==2.0.10
certifi==2024.7.4
cffi==1.17.0
charset-normalizer==3.3.2
click==8.1.7
cloudpathlib==0.18.1
colorful==0.5.6
comm==0.2.2
confection==0.1.5
contourpy==1.2.1
coverage==7.6.1
cryptography==42.0.8
cx_Oracle==8.3.0
cycler==0.12.1
cymem==2.0.8
databricks-sql-connector==3.3.0
de-core-news-md @ https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.7.0/de_core_news_md-3.7.0-py3-none-any.whl#sha256=1426896f135b7e6314637faa9025a3e580c9ba2785372ccffe723dc20b41c493
de-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/de_core_news_sm-3.7.0/de_core_news_sm-3.7.0-py3-none-any.whl#sha256=d88c737eb7eb766f730f6a2dcb99dfcdb81623e1e0d89a9c638a2182ac19c52e
debugpy==1.8.5
decorator==5.1.1
deepdiff==6.7.1
defusedxml==0.7.1
dill==0.3.8
diskcache==5.6.3
distlib==0.3.8
docker==7.1.0
docutils==0.17.1
dtaidistance==2.3.12
ed25519==1.5
elastic-transport==8.13.1
elasticsearch==8.14.0
en-core-web-md @ https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.7.1/en_core_web_md-3.7.1-py3-none-any.whl#sha256=6a0f857a2b4d219c6fa17d455f82430b365bf53171a2d919b9376e5dc9be032e
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.7.1/en_core_web_sm-3.7.1-py3-none-any.whl#sha256=86cc141f63942d4b2c5fcee06630fd6f904788d2f0ab005cce45aadb8fb73889
et-xmlfile==1.1.0
executing==2.0.1
Faker==24.4.0
ff3==1.0.2
filelock==3.15.4
flake8==4.0.1
fonttools==4.53.1
frozendict==2.4.4
frozenlist==1.4.1
future==1.0.0
geohash2==1.1
geojson==3.1.0
google-api-core==2.19.2
google-auth==2.34.0
googleapis-common-protos==1.65.0
greenlet==3.0.3
grpcio==1.66.1
gssapi==1.8.3
hotxlfp==0.0.15
ibm-db-sa==0.4.0
ibm_db==3.2.3
idna==3.7
imagesize==1.4.1
importlib_resources==6.4.0
iniconfig==2.0.0
ipykernel==6.29.5
ipython==8.26.0
isodate==0.6.1
isort==5.13.2
ja-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/ja_core_news_sm-3.7.0/ja_core_news_sm-3.7.0-py3-none-any.whl#sha256=1191e5bbffcc90670146616c274a64850e54d12070bc5846e78a094f2f6fcfca
jedi==0.19.1
Jinja2==3.1.4
jmespath==1.0.1
joblib==1.4.2
jsonschema==4.23.0
jsonschema-specifications==2023.12.1
jupyter_client==8.6.2
jupyter_core==5.7.2
kiwisolver==1.4.5
langcodes==3.4.0
language_data==1.2.0
lazy-object-proxy==1.10.0
Levenshtein==0.25.1
libnfs @ git+https://github.com/sahlberg/libnfs-python.git@b3cab5a6c34dbafc5e58137d7f91f892c0d46dc5
lz4==4.3.3
marisa-trie==1.2.0
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.9.1.post1
matplotlib-inline==0.1.7
mccabe==0.6.1
mdurl==0.1.2
mimesis==15.1.0
moto==5.0.12
msgpack==1.0.8
multidict==6.1.0
murmurhash==1.0.10
mysql-connector-python==8.4.0
mysqlclient==2.2.4
nest-asyncio==1.6.0
networkx==3.3
nl-core-news-lg @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_lg-3.7.0/nl_core_news_lg-3.7.0-py3-none-any.whl#sha256=02194e98105584a6e5008a523a94a5d6e4da2feb0964741646c507c8e20730d4
nl-core-news-md @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_md-3.7.0/nl_core_news_md-3.7.0-py3-none-any.whl#sha256=9b0bacc6d15202bbbd3a9585003d9edec44c6a1f1d819b51e8bc6a6d0b4458a8
nl-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_sm-3.7.0/nl_core_news_sm-3.7.0-py3-none-any.whl#sha256=9255c3ce9e639f0a7aa8e898f4514e6ad803284858241385e045f99637753770
numpy==1.26.4
numpydoc==1.5.0
oauthlib==3.2.2
odbcinst==1.0.1
opencensus==0.11.4
opencensus-context==0.1.3
openpyxl==3.1.5
ordered-set==4.1.0
packaging==24.1
pandas==2.1.4
paramiko==3.4.0
parso==0.8.4
pbr==6.0.0
pexpect==4.9.0
phonenumbers==8.13.42
pillow==10.4.0
pipx==1.6.0
platformdirs==4.2.2
pluggy==1.5.0
ply==3.11
preshed==3.0.9
presidio-analyzer==2.2.353
presidio-anonymizer==2.2.353
prometheus_client==0.20.0
prompt_toolkit==3.0.47
proto-plus==1.24.0
protobuf==5.27.3
psutil==6.0.0
psycopg2-binary==2.9.9
ptyprocess==0.7.0
pure-sasl==0.6.2
pure_eval==0.2.3
py-cpuinfo==9.0.0
py-spy==0.3.14
pyarrow==14.0.2
pyasn1==0.6.1
pyasn1_modules==0.4.1
pycodestyle==2.8.0
pycparser==2.22
pycryptodome==3.20.0
pydantic==2.8.2
pydantic_core==2.20.1
pyfarmhash==0.3.2
pyflakes==2.4.0
Pygments==2.18.0
PyHive==0.7.0
pylint==2.17.7
Pympler==1.1
PyMySQL==1.1.1
PyNaCl==1.5.0
pyodbc==5.1.0
pyOpenSSL==24.2.1
pyparsing==3.1.2
PyRSMQ==0.5.1
pytest==7.4.4
pytest-azurepipelines==1.0.5
pytest-benchmark==4.0.0
pytest-cov==4.1.0
pytest-env==1.1.3
pytest-nunit==1.0.7
python-dateutil==2.9.0.post0
python-Levenshtein==0.25.1
pytz==2024.1
PyYAML==6.0.2
pyzmq==26.1.0
rapidfuzz==3.9.6
ray==2.10.0
redis==5.0.8
referencing==0.35.1
regex==2024.7.24
requests==2.32.3
requests-file==2.1.0
responses==0.25.3
rich==13.7.1
rpds-py==0.20.0
rsa==4.9
ruff==0.5.6
s3transfer==0.10.2
scikit-learn==1.5.1
scipy==1.13.1
seaborn==0.13.2
shapely==2.0.5
shellingham==1.5.4
six==1.16.0
smart-open==7.0.4
snowballstemmer==2.2.0
spacy==3.7.5
spacy-legacy==3.0.12
spacy-loggers==1.0.5
Sphinx==4.5.0
sphinx-autoapi==1.9.0
sphinx-rtd-theme==1.3.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
SQLAlchemy==2.0.32
srsly==2.4.8
sshtunnel==0.4.0
stack-data==0.6.3
stevedore==5.2.0
SudachiDict-core==20240716
SudachiPy==0.6.8
testcontainers==4.8.1
thinc==8.2.5
threadpoolctl==3.5.0
thrift==0.16.0
thrift-sasl==0.4.3
tldextract==5.1.2
tomlkit==0.13.0
tornado==6.4.1
tqdm==4.66.5
traitlets==5.14.3
typer==0.12.3
typing_extensions==4.12.2
tzdata==2024.1
Unidecode==1.3.8
urllib3==2.2.2
userpath==1.9.2
virtualenv==20.26.4
wasabi==1.1.3
wcwidth==0.2.13
weasel==0.4.1
Werkzeug==3.0.3
wrapt==1.16.0
xmltodict==0.13.0
yarl==1.11.1
chrismaeda commented 1 month ago

Here is a reproducible test case for this issue: https://github.com/chrismaeda/testcontainers-python/commit/745231ab17efa03aa249e8271c54ac0730c80b84

  1. pytest fixture and Dockerfile to build a customer mysql8 container using the sql files in modules/mysql/tests/seeds
  2. a pytest method that gets a timeout error on v4.8.2 code
  3. a pytest method that works, using a heavy handed workaround:

As the OP said, the wait_for_logs regex in MySqlContainer._connect does not work for custom mysql images. Since the regex is a string constant, the only workaround that I could figure out is to replace the _connect method on the MySqlContainer instance using a different regex. The pytest method shows that this approach works.

I'm not sure how you want to fix this. The ideal solution seems to be to implement the wait strategies framework in the Java version (https://java.testcontainers.org/features/startup_and_waits/). The least effort solution would be to allow the wait_for_logs regex to be changed at runtime.

chrismaeda commented 4 weeks ago

Submitted test case as PR https://github.com/testcontainers/testcontainers-python/pull/729

alexanderankin commented 4 weeks ago

On a high level, this is a discussion on switching from log waiting to which waiting mechanism? I haven't read the entry point for mysql image yet. I assume the goal is to only support custom image based on the library image with the same entry point script

avaz commented 4 weeks ago

Out of curiosity, why wouldn't the solution that I proposed on my original post be adequate to deal with this issue? I followed the same idea implemented for Postgres as per this commit.

alexanderankin commented 4 weeks ago

Yes sorry let me implement it for mysql as well, I want to confirm some things before agreeing it is the correct solution first