|
| 1 | +# Copyright 2020-present ScyllaDB |
| 2 | +# |
| 3 | +# This file is part of Scylla. |
| 4 | +# |
| 5 | +# Scylla is free software: you can redistribute it and/or modify |
| 6 | +# it under the terms of the GNU Affero General Public License as published by |
| 7 | +# the Free Software Foundation, either version 3 of the License, or |
| 8 | +# (at your option) any later version. |
| 9 | +# |
| 10 | +# Scylla is distributed in the hope that it will be useful, |
| 11 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | +# GNU General Public License for more details. |
| 14 | +# |
| 15 | +# You should have received a copy of the GNU Affero General Public License |
| 16 | +# along with Scylla. If not, see <http://www.gnu.org/licenses/>. |
| 17 | + |
| 18 | +# This file configures pytest for all tests in this directory, and also |
| 19 | +# defines common test fixtures for all of them to use. A "fixture" is some |
| 20 | +# setup which an invididual test requires to run; The fixture has setup code |
| 21 | +# and teardown code, and if multiple tests require the same fixture, it can |
| 22 | +# be set up only once - while still allowing the user to run individual tests |
| 23 | +# and automatically setting up the fixtures they need. |
| 24 | + |
| 25 | +from cassandra.auth import PlainTextAuthProvider |
| 26 | +from cassandra.cluster import Cluster, ConsistencyLevel, ExecutionProfile, EXEC_PROFILE_DEFAULT |
| 27 | +from cassandra.policies import RoundRobinPolicy |
| 28 | +import pathlib |
| 29 | +import pytest |
| 30 | +import ssl |
| 31 | +import sys |
| 32 | + |
| 33 | +sys.path.append(str(pathlib.Path(__file__).resolve().parents[1])) |
| 34 | +from pylib.util import random_string, unique_name |
| 35 | + |
| 36 | + |
| 37 | +# By default, tests run against a CQL server (Scylla or Cassandra) listening |
| 38 | +# on localhost:9042. Add the --host and --port options to allow overiding |
| 39 | +# these defaults. |
| 40 | +def pytest_addoption(parser): |
| 41 | + parser.addoption('--host', action='store', default='localhost', |
| 42 | + help='CQL server host to connect to') |
| 43 | + parser.addoption('--port', action='store', default='9042', |
| 44 | + help='CQL server port to connect to') |
| 45 | + parser.addoption('--ssl', action='store_true', |
| 46 | + help='Connect to CQL via an encrypted TLSv1.2 connection') |
| 47 | + |
| 48 | + |
| 49 | +# "cql" fixture: set up client object for communicating with the CQL API. |
| 50 | +# The host/port combination of the server are determined by the --host and |
| 51 | +# --port options, and defaults to localhost and 9042, respectively. |
| 52 | +# We use scope="session" so that all tests will reuse the same client object. |
| 53 | +@pytest.fixture(scope="session") |
| 54 | +def cql(request): |
| 55 | + profile = ExecutionProfile( |
| 56 | + load_balancing_policy=RoundRobinPolicy(), |
| 57 | + consistency_level=ConsistencyLevel.LOCAL_QUORUM, |
| 58 | + serial_consistency_level=ConsistencyLevel.LOCAL_SERIAL, |
| 59 | + # The default timeout (in seconds) for execute() commands is 10, which |
| 60 | + # should have been more than enough, but in some extreme cases with a |
| 61 | + # very slow debug build running on a very busy machine and a very slow |
| 62 | + # request (e.g., a DROP KEYSPACE needing to drop multiple tables) |
| 63 | + # 10 seconds may not be enough, so let's increase it. See issue #7838. |
| 64 | + request_timeout=120) |
| 65 | + if request.config.getoption('ssl'): |
| 66 | + # Scylla does not support any earlier TLS protocol. If you try, |
| 67 | + # you will get mysterious EOF errors (see issue #6971) :-( |
| 68 | + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) |
| 69 | + else: |
| 70 | + ssl_context = None |
| 71 | + cluster = Cluster(execution_profiles={EXEC_PROFILE_DEFAULT: profile}, |
| 72 | + contact_points=[request.config.getoption('host')], |
| 73 | + port=request.config.getoption('port'), |
| 74 | + # TODO: make the protocol version an option, to allow testing with |
| 75 | + # different versions. If we drop this setting completely, it will |
| 76 | + # mean pick the latest version supported by the client and the server. |
| 77 | + protocol_version=4, |
| 78 | + # Use the default superuser credentials, which work for both Scylla and Cassandra |
| 79 | + auth_provider=PlainTextAuthProvider(username='cassandra', password='cassandra'), |
| 80 | + ssl_context=ssl_context, |
| 81 | + ) |
| 82 | + return cluster.connect() |
| 83 | + |
| 84 | + |
| 85 | +# A function-scoped autouse=True fixture allows us to test after every test |
| 86 | +# that the CQL connection is still alive - and if not report the test which |
| 87 | +# crashed Scylla and stop running any more tests. |
| 88 | +@pytest.fixture(scope="function", autouse=True) |
| 89 | +def cql_test_connection(cql, request): |
| 90 | + yield |
| 91 | + try: |
| 92 | + # We want to run a do-nothing CQL command. "use system" is the |
| 93 | + # closest to do-nothing I could find... |
| 94 | + cql.execute("use system") |
| 95 | + except: # noqa: E722 |
| 96 | + pytest.exit(f"Scylla appears to have crashed in test {request.node.parent.name}::{request.node.name}") |
| 97 | + |
| 98 | + |
| 99 | +# Until Cassandra 4, NetworkTopologyStrategy did not support the option |
| 100 | +# replication_factor (https://issues.apache.org/jira/browse/CASSANDRA-14303). |
| 101 | +# We want to allow these tests to run on Cassandra 3.* (for the convenience |
| 102 | +# of developers who happen to have it installed), so we'll use the older |
| 103 | +# syntax that needs to specify a DC name explicitly. For this, will have |
| 104 | +# a "this_dc" fixture to figure out the name of the current DC, so it can be |
| 105 | +# used in NetworkTopologyStrategy. |
| 106 | +@pytest.fixture(scope="session") |
| 107 | +def this_dc(cql): |
| 108 | + yield cql.execute("SELECT data_center FROM system.local").one()[0] |
| 109 | + |
| 110 | + |
| 111 | +# "test_keyspace" fixture: Creates and returns a temporary keyspace to be |
| 112 | +# used in tests that need a keyspace. The keyspace is created with RF=1, |
| 113 | +# and automatically deleted at the end. We use scope="session" so that all |
| 114 | +# tests will reuse the same keyspace. |
| 115 | +@pytest.fixture(scope="session") |
| 116 | +def test_keyspace(cql, this_dc): |
| 117 | + name = unique_name() |
| 118 | + cql.execute("CREATE KEYSPACE " + name + " WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', '" + |
| 119 | + this_dc + "' : 3 }") |
| 120 | + yield name |
| 121 | + cql.execute("DROP KEYSPACE " + name) |
| 122 | + |
| 123 | + |
| 124 | +# The "scylla_only" fixture can be used by tests for Scylla-only features, |
| 125 | +# which do not exist on Apache Cassandra. A test using this fixture will be |
| 126 | +# skipped if running with "run-cassandra". |
| 127 | +@pytest.fixture(scope="session") |
| 128 | +def scylla_only(cql): |
| 129 | + # We recognize Scylla by checking if there is any system table whose name |
| 130 | + # contains the word "scylla": |
| 131 | + names = [row.table_name for row in cql.execute("SELECT * FROM system_schema.tables WHERE keyspace_name = 'system'")] |
| 132 | + if not any('scylla' in name for name in names): |
| 133 | + pytest.skip('Scylla-only test skipped') |
| 134 | + |
| 135 | + |
| 136 | +# "cassandra_bug" is similar to "scylla_only", except instead of skipping |
| 137 | +# the test, it is expected to fail (xfail) on Cassandra. It should be used |
| 138 | +# in rare cases where we consider Scylla's behavior to be the correct one, |
| 139 | +# and Cassandra's to be the bug. |
| 140 | +@pytest.fixture(scope="session") |
| 141 | +def cassandra_bug(cql): |
| 142 | + # We recognize Scylla by checking if there is any system table whose name |
| 143 | + # contains the word "scylla": |
| 144 | + names = [row.table_name for row in cql.execute("SELECT * FROM system_schema.tables WHERE keyspace_name = 'system'")] |
| 145 | + if not any('scylla' in name for name in names): |
| 146 | + pytest.xfail('A known Cassandra bug') |
0 commit comments