Skip to content

Commit a72dde2

Browse files
nyhxemul
authored andcommitted
test/cqlpy: add test for long table names
Scylla inherited a 48-character limit on the length of table (and keyspace) names from Cassandra 3. It turns out that Cassandra 4 and 5 unintentionally dropped this limit (see history lesson in CASSANDRA-20425), and now Cassandra accepts longer table names. Some Cassandra users are using such longer names and disappointed that Scylla doesn't allow them. This patch includes tests for this feature. One test tries a 48-character table name - it passes on Scylla and all versions of Cassandra. A second test tries a 100-character table name - this one passes on Cassandra version 4 and above (but not on 3), and fails on Scylla so marked "xfail". A third test tries a 500-character table name. This one fails badly on Cassandra (see CASSANDRA-20389), but passes on Scylla today. This test is important because we need to be sure that it continues to pass on Scylla even after the Scylla is fixed to allow the 100-character test. Refs #4480 - an issue we already have about supporting longer names Note on the test implementation: Ideally, the test for a particular table-name length shouldn't just create the table - it should also make sure we can write table to it and flush it, i.e., that sstables can get written correctly. But in practice, these complications are not needed, because in modern Scylla it is the directory name which contains the table's name, and the individual sstable files do not contain the table's name. Just creating the table already creates the long directory name, so that is the part that needs to be tested. If we created this directory successfully, later creating the short-named sstables inside it can't fail. Signed-off-by: Nadav Har'El <[email protected]> Closes #23229
1 parent a82cfbe commit a72dde2

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

test/cqlpy/test_name.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Copyright 2025-present ScyllaDB
2+
#
3+
# SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
4+
5+
#############################################################################
6+
# Tests for limits on the *names* of various objects such as keyspaces,
7+
# tables, indexes, and columns.
8+
#############################################################################
9+
10+
import pytest
11+
import re
12+
from contextlib import contextmanager
13+
from cassandra.protocol import InvalidRequest
14+
from .util import unique_name
15+
16+
# passes_or_raises() is similar to pytest.raises(), except that while raises()
17+
# expects a certain exception must happen, the new passes_or_raises()
18+
# expects the code to either pass (not raise), or if it throws, it must
19+
# throw the specific specified exception.
20+
# This function is useful for tests that want to verify that if some feature
21+
# is still not supported, it must throw some expected graceful error, but
22+
# if one day it *will* be supported, the test should continue to pass.
23+
@contextmanager
24+
def passes_or_raises(expected_exception, match=None):
25+
# Sadly __tracebackhide__=True only drops some of the unhelpful backtrace
26+
# lines. See https://github.com/pytest-dev/pytest/issues/2057
27+
__tracebackhide__ = True
28+
try:
29+
yield
30+
# The user's "with" code is running during the yield. If it didn't
31+
# throw we return from the function - passes_or_raises() succeeded
32+
# in the "passes" case.
33+
return
34+
except expected_exception as err:
35+
if match == None or re.search(match, str(err)):
36+
# The passes_or_raises() succeeded in the "raises" case
37+
return
38+
pytest.fail(f"exception message '{err}' did not match '{match}'")
39+
except Exception as err:
40+
pytest.fail(f"Got unexpected exception type {type(err).__name__} instead of {expected_exception.__name__}: {err}")
41+
42+
# This context manager is similar to new_test_table() - creating a table and
43+
# keeping it alive while the context manager is in scope - but allows the
44+
# caller to pick the name of the table. This is useful to attempt to create
45+
# a table whose name has different lengths or characters.
46+
# Note that if used in a shared keyspace, it is recommended to base the
47+
# given table name on the output of unique_name(), to avoid name clashes.
48+
# See the padded_name() function below as an example.
49+
@contextmanager
50+
def new_named_table(cql, keyspace, table, schema, extra=""):
51+
tbl = keyspace+'.'+table
52+
cql.execute(f'CREATE TABLE {tbl} ({schema}) {extra}')
53+
try:
54+
yield tbl
55+
finally:
56+
cql.execute(f'DROP TABLE {tbl}')
57+
58+
# padded_name() creates a unique name of given length by taking the
59+
# output of unique_name() and padding it with extra 'x' characters:
60+
def padded_name(length):
61+
u = unique_name()
62+
assert length >= len(u)
63+
return u + 'x'*(length-len(u))
64+
65+
# Cassandra's documentation states that "Both keyspace and table name ... are
66+
# limited in size to 48 characters". This was actually only true in Cassandra
67+
# 3, and by Cassandra 4 and 5 this limitation was dropped (see discussion
68+
# in CASSANDRA-20425). So let's split the test for this into two: the first
69+
# test verifies that a 48-character name is allowed, and passes on all versions
70+
# of Scylla and Cassandra:
71+
def test_table_name_length_48(cql, test_keyspace):
72+
schema = 'p int, c int, PRIMARY KEY (p, c)'
73+
with new_named_table(cql, test_keyspace, padded_name(47), schema) as table:
74+
pass
75+
76+
# The second test tries a 100-character name - this one passes on Cassandra 4
77+
# and 5, fails on Cassandra 3, and on Scylla reproduces issue #4480.
78+
@pytest.mark.xfail(reason="#4480")
79+
def test_table_name_length_100(cql, test_keyspace):
80+
schema = 'p int, c int, PRIMARY KEY (p, c)'
81+
with new_named_table(cql, test_keyspace, padded_name(100), schema) as table:
82+
pass
83+
84+
# If we try an even longer table name length, e.g., 500 characters, we run
85+
# into the problem that an attempt to create a file or directory name based
86+
# on the table name will fail. Even if we lift the 48-character limitation
87+
# introduced in Cassandra 3, creating a 500-character name should either
88+
# succeed, or fail gracefully. We mark this test cassandra_bug because
89+
# Cassandra 5 hangs on this test (CASSANDRA-20425 and CASSANDRA-20389).
90+
def test_table_name_length_500(cql, test_keyspace, cassandra_bug):
91+
schema = 'p int, c int, PRIMARY KEY (p, c)'
92+
n = padded_name(500)
93+
with passes_or_raises(InvalidRequest, match=n):
94+
with new_named_table(cql, test_keyspace, n, schema) as table:
95+
pass
96+
97+
# TODO: add tests for the allowed characters in a table name
98+
# TODO: add tests like we have above for table names also for keyspace
99+
# names, index names, function names, column names, etc.

0 commit comments

Comments
 (0)