Skip to content

Commit

Permalink
Adding support for Cassandra and Scylla
Browse files Browse the repository at this point in the history
This add the support for those cassandra based dbs
and their drivers, cassandra-driver, scylla-driver

Ref: https://cassandra.apache.org/
Ref: https://www.scylladb.com/
Ref: https://pypi.org/project/cassandra-driver/
Ref: https://pypi.org/project/scylla-driver/
  • Loading branch information
fruch committed Dec 13, 2022
1 parent 29629e2 commit ad8a8be
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ jobs:
- keycloak.py
- arangodb.py
- azurite.py
- scylladb.py
- cassandra.py
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 2 additions & 0 deletions docs/database.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ Allows to spin up database images such as MySQL, PostgreSQL, MariaDB, Oracle XE,
.. autoclass:: testcontainers.clickhouse.ClickHouseContainer
.. autoclass:: testcontainers.neo4j.Neo4jContainer
.. autoclass:: testcontainers.arangodb.ArangoDbContainer
.. autoclass:: testcontainers.cassandra.CassandraContainer
.. autoclass:: testcontainers.scylla.ScyllaContainer
2 changes: 1 addition & 1 deletion requirements.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,minio,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq,clickhouse,keycloak,arangodb,azurite]
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,minio,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq,clickhouse,keycloak,arangodb,azurite,cassandra,scylla]
codecov>=2.1.0
cryptography<37
flake8<3.8.0 # 3.8.0 adds a dependency on importlib-metadata which conflicts with other packages.
Expand Down
21 changes: 18 additions & 3 deletions requirements/3.10.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ bleach==5.0.1
# via readme-renderer
cachetools==5.2.0
# via google-auth
cassandra-driver==3.25.0
# via testcontainers
certifi==2022.12.7
# via
# minio
Expand All @@ -48,6 +50,8 @@ cffi==1.15.1
# pynacl
charset-normalizer==2.1.1
# via requests
click==8.1.3
# via geomet
clickhouse-driver==0.2.5
# via testcontainers
codecov==2.1.12
Expand Down Expand Up @@ -96,6 +100,10 @@ exceptiongroup==1.0.4
# trio
flake8==3.7.9
# via -r requirements.in
geomet==0.2.1.post1
# via
# cassandra-driver
# scylla-driver
google-api-core[grpc]==2.11.0
# via google-cloud-pubsub
google-auth==2.15.0
Expand Down Expand Up @@ -227,7 +235,7 @@ pytest==7.2.0
# pytest-cov
pytest-cov==4.0.0
# via -r requirements.in
python-arango==7.5.3
python-arango==7.5.4
# via testcontainers
python-dateutil==2.8.2
# via pg8000
Expand All @@ -245,7 +253,9 @@ pytz==2022.6
pytz-deprecation-shim==0.1.0.post0
# via tzlocal
pyyaml==5.4.1
# via docker-compose
# via
# docker-compose
# scylla-driver
readme-renderer==37.3
# via twine
redis==4.4.0
Expand Down Expand Up @@ -281,6 +291,8 @@ rsa==4.9
# python-jose
scramp==1.4.4
# via pg8000
scylla-driver==3.25.10
# via testcontainers
secretstorage==3.3.3
# via keyring
selenium==4.7.2
Expand All @@ -289,13 +301,16 @@ six==1.16.0
# via
# azure-core
# bleach
# cassandra-driver
# dockerpty
# ecdsa
# geomet
# google-auth
# isodate
# jsonschema
# paramiko
# python-dateutil
# scylla-driver
# websocket-client
sniffio==1.3.0
# via trio
Expand All @@ -317,7 +332,7 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
sqlalchemy==1.4.44
sqlalchemy==1.4.45
# via testcontainers
texttable==1.6.7
# via docker-compose
Expand Down
21 changes: 18 additions & 3 deletions requirements/3.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ bleach==5.0.1
# via readme-renderer
cachetools==5.2.0
# via google-auth
cassandra-driver==3.25.0
# via testcontainers
certifi==2022.12.7
# via
# minio
Expand All @@ -52,6 +54,8 @@ cffi==1.15.1
# pynacl
charset-normalizer==2.1.1
# via requests
click==8.1.3
# via geomet
clickhouse-driver==0.2.5
# via testcontainers
codecov==2.1.12
Expand Down Expand Up @@ -100,6 +104,10 @@ exceptiongroup==1.0.4
# trio
flake8==3.7.9
# via -r requirements.in
geomet==0.2.1.post1
# via
# cassandra-driver
# scylla-driver
google-api-core[grpc]==2.11.0
# via google-cloud-pubsub
google-auth==2.15.0
Expand Down Expand Up @@ -232,7 +240,7 @@ pytest==7.2.0
# pytest-cov
pytest-cov==4.0.0
# via -r requirements.in
python-arango==7.5.3
python-arango==7.5.4
# via testcontainers
python-dateutil==2.8.2
# via pg8000
Expand All @@ -250,7 +258,9 @@ pytz==2022.6
pytz-deprecation-shim==0.1.0.post0
# via tzlocal
pyyaml==5.4.1
# via docker-compose
# via
# docker-compose
# scylla-driver
readme-renderer==37.3
# via twine
redis==4.4.0
Expand Down Expand Up @@ -286,6 +296,8 @@ rsa==4.9
# python-jose
scramp==1.4.4
# via pg8000
scylla-driver==3.25.10
# via testcontainers
secretstorage==3.3.3
# via keyring
selenium==4.7.2
Expand All @@ -294,13 +306,16 @@ six==1.16.0
# via
# azure-core
# bleach
# cassandra-driver
# dockerpty
# ecdsa
# geomet
# google-auth
# isodate
# jsonschema
# paramiko
# python-dateutil
# scylla-driver
# websocket-client
sniffio==1.3.0
# via trio
Expand All @@ -322,7 +337,7 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
sqlalchemy==1.4.44
sqlalchemy==1.4.45
# via testcontainers
texttable==1.6.7
# via docker-compose
Expand Down
21 changes: 18 additions & 3 deletions requirements/3.9.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ bleach==5.0.1
# via readme-renderer
cachetools==5.2.0
# via google-auth
cassandra-driver==3.25.0
# via testcontainers
certifi==2022.12.7
# via
# minio
Expand All @@ -48,6 +50,8 @@ cffi==1.15.1
# pynacl
charset-normalizer==2.1.1
# via requests
click==8.1.3
# via geomet
clickhouse-driver==0.2.5
# via testcontainers
codecov==2.1.12
Expand Down Expand Up @@ -96,6 +100,10 @@ exceptiongroup==1.0.4
# trio
flake8==3.7.9
# via -r requirements.in
geomet==0.2.1.post1
# via
# cassandra-driver
# scylla-driver
google-api-core[grpc]==2.11.0
# via google-cloud-pubsub
google-auth==2.15.0
Expand Down Expand Up @@ -228,7 +236,7 @@ pytest==7.2.0
# pytest-cov
pytest-cov==4.0.0
# via -r requirements.in
python-arango==7.5.3
python-arango==7.5.4
# via testcontainers
python-dateutil==2.8.2
# via pg8000
Expand All @@ -246,7 +254,9 @@ pytz==2022.6
pytz-deprecation-shim==0.1.0.post0
# via tzlocal
pyyaml==5.4.1
# via docker-compose
# via
# docker-compose
# scylla-driver
readme-renderer==37.3
# via twine
redis==4.4.0
Expand Down Expand Up @@ -282,6 +292,8 @@ rsa==4.9
# python-jose
scramp==1.4.4
# via pg8000
scylla-driver==3.25.10
# via testcontainers
secretstorage==3.3.3
# via keyring
selenium==4.7.2
Expand All @@ -290,13 +302,16 @@ six==1.16.0
# via
# azure-core
# bleach
# cassandra-driver
# dockerpty
# ecdsa
# geomet
# google-auth
# isodate
# jsonschema
# paramiko
# python-dateutil
# scylla-driver
# websocket-client
sniffio==1.3.0
# via trio
Expand All @@ -318,7 +333,7 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
sqlalchemy==1.4.44
sqlalchemy==1.4.45
# via testcontainers
texttable==1.6.7
# via docker-compose
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
'keycloak': ['python-keycloak'],
'arangodb': ['python-arango'],
'azurite': ['azure-storage-blob'],
'cassandra': ['cassandra-driver'],
'scylla': ['scylla-driver'],
},
long_description_content_type="text/x-rst",
long_description=long_description,
Expand Down
46 changes: 46 additions & 0 deletions testcontainers/cassandra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from testcontainers.core.config import MAX_TRIES
from testcontainers.core.generic import DockerContainer
from testcontainers.core.waiting_utils import wait_container_is_ready, wait_for_logs


class CassandraContainer(DockerContainer):
"""
Cassandra database container.
Example
-------
::
with CassandraContainer() as cassandra:
cluster = cassandra.get_cluster()
with cluster.connect() as session:
session.execute(
"CREATE KEYSPACE keyspace1 WITH replication = "
"{'class': 'SimpleStrategy', 'replication_factor': '1'};")
"""
def __init__(self, image="rinscy/cassandra:latest", ports_to_expose=[9042]):
super(CassandraContainer, self).__init__(image)
self.ports_to_expose = ports_to_expose
self.with_exposed_ports(*self.ports_to_expose)

@wait_container_is_ready()
def _connect(self):
wait_for_logs(
self,
predicate="Starting listening for CQL clients",
timeout=MAX_TRIES)
cluster = self.get_cluster()
cluster.connect()

def start(self):
super(CassandraContainer, self).start()
self._connect()
return self

def get_cluster(self, **kwargs):
from cassandra.cluster import Cluster
container = self.get_wrapped_container()
container.reload()
hostname = container.attrs['NetworkSettings']['IPAddress']
return Cluster(contact_points=[hostname], **kwargs)
47 changes: 47 additions & 0 deletions testcontainers/scylla.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from testcontainers.core.config import MAX_TRIES
from testcontainers.core.generic import DockerContainer
from testcontainers.core.waiting_utils import wait_container_is_ready, wait_for_logs


class ScyllaContainer(DockerContainer):
"""
Scylla database container.
Example
-------
::
with ScyllaContainer() as scylla:
cluster = scylla.get_cluster()
with cluster.connect() as session:
session.execute(
"CREATE KEYSPACE keyspace1 WITH replication "
"= {'class': 'SimpleStrategy', 'replication_factor': '1'};")
"""
def __init__(self, image="scylladb/scylla:latest", ports_to_expose=[9042]):
super(ScyllaContainer, self).__init__(image)
self.ports_to_expose = ports_to_expose
self.with_exposed_ports(*self.ports_to_expose)
self.with_command("--skip-wait-for-gossip-to-settle=0")

@wait_container_is_ready()
def _connect(self):
wait_for_logs(
self,
predicate="Starting listening for CQL clients",
timeout=MAX_TRIES)
cluster = self.get_cluster()
cluster.connect()

def start(self):
super(ScyllaContainer, self).start()
self._connect()
return self

def get_cluster(self, **kwargs):
from cassandra.cluster import Cluster
container = self.get_wrapped_container()
container.reload()
hostname = container.attrs['NetworkSettings']['IPAddress']
return Cluster(contact_points=[hostname], **kwargs)
18 changes: 18 additions & 0 deletions tests/test_cassandra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from testcontainers.cassandra import CassandraContainer


def test_docker_run_cassandra():
with CassandraContainer() as cassandra:
cluster = cassandra.get_cluster()
with cluster.connect() as session:
session.execute(
"CREATE KEYSPACE keyspace1 WITH replication = "
"{'class': 'SimpleStrategy', 'replication_factor': '1'};")
session.execute(
"CREATE TABLE keyspace1.table1 (key1 int, key2 int, PRIMARY KEY (key1));")
session.execute("INSERT INTO keyspace1.table1 (key1,key2) values (1,2);")

response = session.execute("SELECT * FROM keyspace1.table1")

assert response.one().key1 == 1
assert response.one().key2 == 2
Loading

0 comments on commit ad8a8be

Please sign in to comment.