From 6425364cb963cdf8da0cbccfd77faa371afc225a Mon Sep 17 00:00:00 2001 From: Dmitry Maslennikov Date: Tue, 22 Aug 2023 17:47:48 +0400 Subject: [PATCH] InterSystems IRIS support --- .github/workflows/main.yml | 1 + CODEOWNERS | 1 + iris/README.rst | 1 + iris/setup.py | 19 +++++++++ iris/testcontainers/iris/__init__.py | 61 ++++++++++++++++++++++++++++ iris/tests/test_iris.py | 12 ++++++ requirements.in | 1 + 7 files changed, 96 insertions(+) create mode 100644 iris/README.rst create mode 100644 iris/setup.py create mode 100644 iris/testcontainers/iris/__init__.py create mode 100644 iris/tests/test_iris.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84b8ca10..e8899a7e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,6 +28,7 @@ jobs: - core - elasticsearch - google + - iris - kafka - keycloak - localstack diff --git a/CODEOWNERS b/CODEOWNERS index aa08e105..d8293b78 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,6 +5,7 @@ # /core /elasticsearch @nivm @daTokenizer /google @tillahoffmann +/iris @daimor /kafka @ash1425 /keycloak @timbmg /localstack @ImFlog diff --git a/iris/README.rst b/iris/README.rst new file mode 100644 index 00000000..6c52f473 --- /dev/null +++ b/iris/README.rst @@ -0,0 +1 @@ +.. autoclass:: testcontainers.iris.IRISContainer diff --git a/iris/setup.py b/iris/setup.py new file mode 100644 index 00000000..08b3fb25 --- /dev/null +++ b/iris/setup.py @@ -0,0 +1,19 @@ +from setuptools import setup, find_namespace_packages + +description = "InterSystems IRIS component of testcontainers-python." + +setup( + name="testcontainers-iris", + version="0.0.1rc1", + packages=find_namespace_packages(), + description=description, + long_description=description, + long_description_content_type="text/x-rst", + url="https://github.com/testcontainers/testcontainers-python", + install_requires=[ + "testcontainers-core", + "sqlalchemy", + "sqlalchemy-iris", + ], + python_requires=">=3.7", +) diff --git a/iris/testcontainers/iris/__init__.py b/iris/testcontainers/iris/__init__.py new file mode 100644 index 00000000..9226fecf --- /dev/null +++ b/iris/testcontainers/iris/__init__.py @@ -0,0 +1,61 @@ +import os +from typing import Optional +from testcontainers.core.config import TIMEOUT +from testcontainers.core.generic import DbContainer +from testcontainers.core.utils import raise_for_deprecated_parameter +from testcontainers.core.waiting_utils import wait_for_logs, wait_container_is_ready + + +class IRISContainer(DbContainer): + """ + InterSystems IRIS database container. + + Example: + + The example spins up a IRIS database and connects to it using the :code:`intersystems-iris` + driver. + + .. doctest:: + + >>> from testcontainers.iris import IRISContainer + >>> import sqlalchemy + + >>> iris_container = IRISContainer("intersystemsdc/iris-community:latest") + >>> with iris_container as iris: + ... engine = sqlalchemy.create_engine(iris.get_connection_url()) + ... with engine.begin() as connection: + ... result = connection.execute(sqlalchemy.text("select $zversion")) + ... version, = result.fetchone() + >>> version + 'IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2023.2 (Build 227U)...' + """ + + def __init__(self, image: str = "intersystemsdc/iris-community:latest", port: int = 1972, + username: Optional[str] = None, password: Optional[str] = None, + dbname: Optional[str] = None, driver: str = "iris", **kwargs) -> None: + raise_for_deprecated_parameter(kwargs, "user", "username") + super(IRISContainer, self).__init__(image=image, **kwargs) + self.username = username or os.environ.get("IRIS_USERNAME", "test") + self.password = password or os.environ.get("IRIS_PASSWORD", "test") + self.dbname = dbname or os.environ.get("IRIS_NAMESPACE", "USER") + self.port = port + self.driver = driver + + self.with_exposed_ports(self.port) + + def _configure(self) -> None: + self.with_env("IRIS_USERNAME", self.username) + self.with_env("IRIS_PASSWORD", self.password) + self.with_env("IRIS_NAMESPACE", self.dbname) + + def get_connection_url(self, host=None) -> str: + return super()._create_connection_url( + dialect=f"iris", username=self.username, + password=self.password, dbname=self.dbname, host=host, + port=self.port, + ) + + @wait_container_is_ready() + def _connect(self): + wait_for_logs(self, predicate="Enabling logons", timeout=TIMEOUT) + super()._connect() diff --git a/iris/tests/test_iris.py b/iris/tests/test_iris.py new file mode 100644 index 00000000..95820470 --- /dev/null +++ b/iris/tests/test_iris.py @@ -0,0 +1,12 @@ +import sqlalchemy +from testcontainers.iris import IRISContainer + + +def test_docker_run_iris(): + iris_container = IRISContainer("intersystemsdc/iris-community:2023.1.1.380.0-zpm") + with iris_container as iris: + engine = sqlalchemy.create_engine(iris.get_connection_url()) + with engine.begin() as connection: + result = connection.execute(sqlalchemy.text("select $zversion")) + for row in result: + assert "2023.1.1 (Build 380U)" in row[0] diff --git a/requirements.in b/requirements.in index e9e12261..d173a7fe 100644 --- a/requirements.in +++ b/requirements.in @@ -5,6 +5,7 @@ -e file:compose -e file:elasticsearch -e file:google +-e file:iris -e file:kafka -e file:keycloak -e file:localstack