Skip to content

Commit f09e2d0

Browse files
absurdfarcedkropachev
authored andcommitted
PYTHON-1297 Convert to pytest for running unit and integration tests (datastax#1215)
1 parent 972635b commit f09e2d0

16 files changed

+79
-41
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ build
1212
MANIFEST
1313
dist
1414
.coverage
15-
nosetests.xml
1615
cover/
1716
docs/_build/
1817
tests/integration/ccm

README-dev.rst

+10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ environment variable::
4848

4949
SCYLLA_VERSION="release:5.1" python -m pytest tests/integration/standard tests/integration/cqlengine/
5050

51+
Or you can specify a scylla/cassandra directory (to test unreleased versions)::
52+
53+
SCYLLA_VERSION=/path/to/scylla pytest tests/integration/standard/
54+
55+
Specifying the usage of an already running Scylla cluster
56+
------------------------------------------------------------
57+
The test will start the appropriate Scylla clusters when necessary but if you don't want this to happen because a Scylla cluster is already running the flag ``USE_CASS_EXTERNAL`` can be used, for example::
58+
59+
USE_CASS_EXTERNAL=1 SCYLLA_VERSION='release:5.1' pytest tests/integration/standard
60+
5161
Specify a Protocol Version for Tests
5262
------------------------------------
5363
The protocol version defaults to:

cassandra/io/asyncorereactor.py

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import sys
2525
import ssl
2626

27-
2827
try:
2928
from weakref import WeakSet
3029
except ImportError:

cassandra/io/libevreactor.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import time
2323

2424
from cassandra import DependencyException
25-
from cassandra.connection import (Connection, ConnectionShutdown,
26-
NONBLOCKING, Timer, TimerManager)
2725
try:
2826
import cassandra.io.libevwrapper as libev
2927
except ImportError:
@@ -35,6 +33,9 @@
3533
"for instructions on installing build dependencies and building "
3634
"the C extension.")
3735

36+
from cassandra.connection import (Connection, ConnectionShutdown,
37+
NONBLOCKING, Timer, TimerManager)
38+
3839

3940
log = logging.getLogger(__name__)
4041

cassandra/io/twistedreactor.py

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ def maybe_start(self):
102102
self._thread.start()
103103
atexit.register(partial(_cleanup, weakref.ref(self)))
104104

105+
def _reactor_stopped(self):
106+
return reactor._stopped
107+
105108
def _cleanup(self):
106109
if self._thread:
107110
reactor.callFromThread(reactor.stop)

setup.py

-28
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,6 @@
1818
import json
1919
import warnings
2020
from pathlib import Path
21-
22-
if __name__ == '__main__' and len(sys.argv) > 1:
23-
if sys.argv[1] == "gevent_nosetests":
24-
print("Running gevent tests")
25-
from gevent.monkey import patch_all
26-
patch_all()
27-
elif sys.argv[1] == "eventlet_nosetests":
28-
print("Running eventlet tests")
29-
from eventlet import monkey_patch
30-
monkey_patch()
31-
3221
from setuptools.command.build_ext import build_ext
3322
from setuptools import Extension, Command, setup
3423
from setuptools.errors import (CCompilerError, PlatformError,
@@ -40,17 +29,6 @@
4029
except ImportError:
4130
has_subprocess = False
4231

43-
try:
44-
from nose.commands import nosetests
45-
except ImportError:
46-
gevent_nosetests = None
47-
eventlet_nosetests = None
48-
else:
49-
class gevent_nosetests(nosetests):
50-
description = "run nosetests with gevent monkey patching"
51-
52-
class eventlet_nosetests(nosetests):
53-
description = "run nosetests with eventlet monkey patching"
5432

5533
has_cqlengine = False
5634
if __name__ == '__main__' and len(sys.argv) > 1 and sys.argv[1] == "install":
@@ -424,12 +402,6 @@ def pre_build_check():
424402
def run_setup(extensions):
425403

426404
kw = {'cmdclass': {'doc': DocCommand}}
427-
if gevent_nosetests is not None:
428-
kw['cmdclass']['gevent_nosetests'] = gevent_nosetests
429-
430-
if eventlet_nosetests is not None:
431-
kw['cmdclass']['eventlet_nosetests'] = eventlet_nosetests
432-
433405
kw['cmdclass']['build_ext'] = build_extensions
434406
kw['ext_modules'] = [Extension('DUMMY', [])] # dummy extension makes sure build_ext is called for install
435407

tests/integration/cloud/conftest.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pytest
2+
3+
from tests.integration.cloud import setup_package, teardown_package
4+
5+
@pytest.fixture(scope='session', autouse=True)
6+
def setup_and_teardown_packages():
7+
setup_package()
8+
yield
9+
teardown_package()

tests/integration/conftest.py

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import pytest
55
from ccmlib.cluster_factory import ClusterFactory as CCMClusterFactory
66

7+
from tests.integration import teardown_package
8+
79
from . import CLUSTER_NAME, SINGLE_NODE_CLUSTER_NAME, MULTIDC_CLUSTER_NAME
810
from . import path as ccm_path
911

@@ -22,3 +24,9 @@ def cleanup_clusters():
2224
cluster.clear()
2325
except FileNotFoundError:
2426
pass
27+
28+
@pytest.fixture(scope='session', autouse=True)
29+
def setup_and_teardown_packages():
30+
print('setup')
31+
yield
32+
teardown_package()

tests/integration/cqlengine/conftest.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333

3434
from cassandra.cqlengine import connection
3535
from cassandra.cqlengine.management import create_keyspace_simple, drop_keyspace, CQLENG_ALLOW_SCHEMA_MANAGEMENT
36-
from tests.integration import use_single_node
36+
from tests.integration import use_single_node, teardown_package as parent_teardown_package
37+
from tests.integration.cqlengine import setup_package, teardown_package
3738

3839
from . import setup_connection, DEFAULT_KEYSPACE
3940

@@ -52,3 +53,11 @@ def cqlengine_fixture():
5253

5354
drop_keyspace(DEFAULT_KEYSPACE)
5455
connection.unregister_connection("default")
56+
57+
58+
@pytest.fixture(scope='session', autouse=True)
59+
def setup_and_teardown_packages():
60+
setup_package()
61+
yield
62+
teardown_package()
63+
parent_teardown_package()

tests/integration/cqlengine/test_batch_query.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414
import warnings
1515

16+
import pytest
17+
1618
from cassandra.cqlengine import columns
1719
from cassandra.cqlengine.management import drop_table, sync_table
1820
from cassandra.cqlengine.models import Model
@@ -217,8 +219,7 @@ def test_callbacks_work_multiple_times(self):
217219
def my_callback(*args, **kwargs):
218220
call_history.append(args)
219221

220-
with warnings.catch_warnings(record=True) as w:
221-
warnings.simplefilter("always")
222+
with pytest.warns() as w:
222223
with BatchQuery() as batch:
223224
batch.add_callback(my_callback)
224225
batch.execute()
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pytest
2+
3+
from tests.integration.simulacron import teardown_package
4+
5+
@pytest.fixture(scope='session', autouse=True)
6+
def setup_and_teardown_packages():
7+
print('setup')
8+
yield
9+
teardown_package()
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pytest
2+
import logging
3+
4+
# from https://github.com/streamlit/streamlit/pull/5047/files
5+
def pytest_sessionfinish():
6+
# We're not waiting for scriptrunner threads to cleanly close before ending the PyTest,
7+
# which results in raised exception ValueError: I/O operation on closed file.
8+
# This is well known issue in PyTest, check out these discussions for more:
9+
# * https://github.com/pytest-dev/pytest/issues/5502
10+
# * https://github.com/pytest-dev/pytest/issues/5282
11+
# To prevent the exception from being raised on pytest_sessionfinish
12+
# we disable exception raising in logging module
13+
logging.raiseExceptions = False

tests/unit/io/test_asyncorereactor.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import platform
1415
import unittest
1516

1617
from unittest.mock import patch
@@ -64,7 +65,8 @@ def tearDownClass(cls):
6465
except:
6566
pass
6667

67-
68+
has_asyncore = Version(platform.python_version()) < Version("3.12.0")
69+
@unittest.skipUnless(has_asyncore, "asyncore has been removed in Python 3.12")
6870
class AsyncoreConnectionTest(ReactorTestMixin, AsyncorePatcher):
6971

7072
connection_class = AsyncoreConnection
@@ -75,6 +77,7 @@ def setUp(self):
7577
raise unittest.SkipTest("Can't test asyncore with monkey patching")
7678

7779

80+
@unittest.skipUnless(has_asyncore, "asyncore has been removed in Python 3.12")
7881
class TestAsyncoreTimer(TimerTestMixin, AsyncorePatcher):
7982
connection_class = AsyncoreConnection
8083

tests/unit/io/test_libevreactor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@
1414
import unittest
1515

1616
from unittest.mock import patch, Mock
17-
import weakref
1817
import socket
1918

20-
from tests import is_monkey_patched
21-
from tests.unit.io.utils import ReactorTestMixin, TimerTestMixin, noop_if_monkey_patched
2219
from cassandra import DependencyException
2320

2421
try:
@@ -27,6 +24,9 @@
2724
except (ImportError, DependencyException):
2825
LibevConnection = None # noqa
2926

27+
from tests import is_monkey_patched
28+
from tests.unit.io.utils import ReactorTestMixin, TimerTestMixin, noop_if_monkey_patched
29+
3030

3131
class LibevConnectionTest(ReactorTestMixin, unittest.TestCase):
3232

tests/unit/io/test_twistedreactor.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def setUp(self):
6666
self.tr.protocol = self.obj_ut
6767

6868
def tearDown(self):
69-
pass
69+
loop = twistedreactor.TwistedConnection._loop
70+
if not loop._reactor_stopped():
71+
loop._cleanup()
7072

7173
def test_makeConnection(self):
7274
"""

tests/unit/io/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def test_timer_cancellation(self):
178178
timer = self.create_timer(timeout, callback.invoke)
179179
timer.cancel()
180180
# Release context allow for timer thread to run.
181-
time.sleep(.2)
181+
time.sleep(timeout * 2)
182182
timer_manager = self._timers
183183
# Assert that the cancellation was honored
184184
self.assertFalse(timer_manager._queue)

0 commit comments

Comments
 (0)