Skip to content

Commit 0064834

Browse files
author
Alejo Sanchez
committed
test.py topology: test with asyncio
Run test async using a wrapper for Cassandra python driver's future. The wrapper was suggested by a user and brought forward by @fruch. It's based on https://stackoverflow.com/a/49351069 . Redefine pytest event_loop fixture to avoid issues with fixtures with scope bigger than function (like keyspace). See pytest-dev/pytest-asyncio#68 Convert sample test_null to async. More useful test cases will come afterwards. Signed-off-by: Alejo Sanchez <[email protected]>
1 parent 6c818f8 commit 0064834

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

test/conftest.py

+43
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
# fixtures directly from test/pylib).
1111
#
1212
#
13+
import asyncio
1314
from cassandra.auth import PlainTextAuthProvider # type: ignore
1415
from cassandra.cluster import Cluster, ConsistencyLevel # type: ignore
1516
from cassandra.cluster import ExecutionProfile, EXEC_PROFILE_DEFAULT # type: ignore
17+
from cassandra.cluster import Session, ResponseFuture # type: ignore
1618
from cassandra.policies import RoundRobinPolicy # type: ignore
1719
from test.pylib.util import unique_name # type: ignore
1820
import pytest
@@ -30,6 +32,47 @@ def pytest_addoption(parser):
3032
parser.addoption('--ssl', action='store_true',
3133
help='Connect to CQL via an encrypted TLSv1.2 connection')
3234

35+
36+
# Change default pytest-asyncio event_loop fixture scope to session to
37+
# allow async fixtures with scope larger than function. (e.g. keyspace fixture)
38+
# See https://github.com/pytest-dev/pytest-asyncio/issues/68
39+
@pytest.fixture(scope="session")
40+
def event_loop(request):
41+
loop = asyncio.get_event_loop_policy().new_event_loop()
42+
yield loop
43+
loop.close()
44+
45+
46+
def _wrap_future(f: ResponseFuture) -> asyncio.Future:
47+
"""Wrap a cassandra Future into an asyncio.Future object.
48+
49+
Args:
50+
f: future to wrap
51+
52+
Returns:
53+
And asyncio.Future object which can be awaited.
54+
"""
55+
loop = asyncio.get_event_loop()
56+
aio_future = loop.create_future()
57+
58+
def on_result(result):
59+
loop.call_soon_threadsafe(aio_future.set_result, result)
60+
61+
def on_error(exception, *_):
62+
loop.call_soon_threadsafe(aio_future.set_exception, exception)
63+
64+
f.add_callback(on_result)
65+
f.add_errback(on_error)
66+
return aio_future
67+
68+
69+
def run_async(self, *args, **kwargs) -> asyncio.Future:
70+
return _wrap_future(self.execute_async(*args, **kwargs))
71+
72+
73+
Session.run_async = run_async
74+
75+
3376
# "cql" fixture: set up client object for communicating with the CQL API.
3477
# The host/port combination of the server are determined by the --host and
3578
# --port options, and defaults to localhost and 9042, respectively.

test/topology/test_null.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99

1010

1111
@pytest.fixture(scope="module")
12-
def table1(cql, test_keyspace):
12+
async def table1(cql, test_keyspace):
1313
table = test_keyspace + "." + unique_name()
14-
cql.execute(f"CREATE TABLE {table} (p text, c text, v text, primary key (p, c))")
14+
await cql.run_async(f"CREATE TABLE {table} (p text, c text, v text, primary key (p, c))")
1515
yield table
16-
cql.execute("DROP TABLE " + table)
16+
await cql.run_async("DROP TABLE " + table)
1717

1818

19-
def test_delete_empty_string_key(cql, table1):
19+
@pytest.mark.asyncio
20+
async def test_delete_empty_string_key(cql, table1):
2021
s = "foobar"
2122
# An empty-string clustering *is* allowed:
22-
cql.execute(f"DELETE FROM {table1} WHERE p='{s}' AND c=''")
23+
await cql.run_async(f"DELETE FROM {table1} WHERE p='{s}' AND c=''")
2324
# But an empty-string partition key is *not* allowed, with a specific
2425
# error that a "Key may not be empty":
2526
with pytest.raises(InvalidRequest, match='Key may not be empty'):
26-
cql.execute(f"DELETE FROM {table1} WHERE p='' AND c='{s}'")
27+
await cql.run_async(f"DELETE FROM {table1} WHERE p='' AND c='{s}'")

0 commit comments

Comments
 (0)