Source code for pytest_databases.docker.mysql

from __future__ import annotations

import contextlib
from dataclasses import dataclass
from typing import TYPE_CHECKING

import mysql.connector
import pytest

from pytest_databases._service import DockerService, ServiceContainer
from pytest_databases.helpers import get_xdist_worker_num

if TYPE_CHECKING:
    from collections.abc import Generator

    from mysql.connector.abstracts import MySQLConnectionAbstract

    from pytest_databases.types import XdistIsolationLevel


[docs] @dataclass class MySQLService(ServiceContainer): db: str user: str password: str
[docs] @pytest.fixture(scope="session") def xdist_mysql_isolation_level() -> XdistIsolationLevel: return "database"
@contextlib.contextmanager def _provide_mysql_service( docker_service: DockerService, image: str, name: str, isolation_level: XdistIsolationLevel, ) -> Generator[MySQLService, None, None]: user = "app" password = "super-secret" root_password = "super-secret" database = "db" def check(_service: ServiceContainer) -> bool: try: conn = mysql.connector.connect( host=_service.host, port=_service.port, user=user, database=database, password=password, ) except mysql.connector.errors.OperationalError as exc: if "Lost connection" in exc.msg: # type: ignore return False raise try: with conn.cursor() as cursor: cursor.execute("select 1 as is_available") resp = cursor.fetchone() return resp is not None and resp[0] == 1 # type: ignore finally: with contextlib.suppress(Exception): conn.close() worker_num = get_xdist_worker_num() db_name = "pytest_databases" if worker_num is not None: suffix = f"_{worker_num}" if isolation_level == "server": name += suffix else: db_name += suffix with docker_service.run( image=image, check=check, container_port=3306, name=name, env={ "MYSQL_ROOT_PASSWORD": root_password, "MYSQL_PASSWORD": password, "MYSQL_USER": user, "MYSQL_DATABASE": database, "MYSQL_ROOT_HOST": "%", "LANG": "C.UTF-8", }, timeout=60, pause=0.5, exec_after_start=( f'mysql --user=root --password={root_password} -e "CREATE DATABASE {db_name};' f"GRANT ALL PRIVILEGES ON *.* TO '{user}'@'%'; " 'FLUSH PRIVILEGES;"' ), transient=isolation_level == "server", ) as service: yield MySQLService( db=db_name, host=service.host, port=service.port, user=user, password=password, )
[docs] @pytest.fixture(scope="session") def mysql_service(mysql_8_service: MySQLService) -> MySQLService: return mysql_8_service
[docs] @pytest.fixture(scope="session") def mysql_56_service( docker_service: DockerService, xdist_mysql_isolation_level: XdistIsolationLevel, ) -> Generator[MySQLService, None, None]: with _provide_mysql_service( image="mysql:5.6", name="mysql-56", docker_service=docker_service, isolation_level=xdist_mysql_isolation_level, ) as service: yield service
[docs] @pytest.fixture(scope="session") def mysql_57_service( docker_service: DockerService, xdist_mysql_isolation_level: XdistIsolationLevel, ) -> Generator[MySQLService, None, None]: with _provide_mysql_service( image="mysql:5.7", name="mysql-57", docker_service=docker_service, isolation_level=xdist_mysql_isolation_level, ) as service: yield service
[docs] @pytest.fixture(scope="session") def mysql_8_service( docker_service: DockerService, xdist_mysql_isolation_level: XdistIsolationLevel, ) -> Generator[MySQLService, None, None]: with _provide_mysql_service( image="mysql:8", name="mysql-8", docker_service=docker_service, isolation_level=xdist_mysql_isolation_level, ) as service: yield service
[docs] @pytest.fixture(scope="session") def mysql_56_connection(mysql_56_service: MySQLService) -> Generator[MySQLConnectionAbstract, None, None]: with mysql.connector.connect( host=mysql_56_service.host, port=mysql_56_service.port, user=mysql_56_service.user, database=mysql_56_service.db, password=mysql_56_service.password, ) as conn: yield conn # type: ignore
[docs] @pytest.fixture(scope="session") def mysql_57_connection(mysql_57_service: MySQLService) -> Generator[MySQLConnectionAbstract, None, None]: with mysql.connector.connect( host=mysql_57_service.host, port=mysql_57_service.port, user=mysql_57_service.user, database=mysql_57_service.db, password=mysql_57_service.password, ) as conn: yield conn # type: ignore
[docs] @pytest.fixture(scope="session") def mysql_connection(mysql_8_connection: MySQLConnectionAbstract) -> MySQLConnectionAbstract: return mysql_8_connection
[docs] @pytest.fixture(scope="session") def mysql_8_connection(mysql_8_service: MySQLService) -> Generator[MySQLConnectionAbstract, None, None]: with mysql.connector.connect( host=mysql_8_service.host, port=mysql_8_service.port, user=mysql_8_service.user, database=mysql_8_service.db, password=mysql_8_service.password, ) as conn: yield conn # type: ignore