Fix hygiene issues for cqlshlib

patch by Brad Schoening; reviewed by Stefan Miklosovic and Berenguer Blasi for CASSANDRA-19450
This commit is contained in:
Brad Schoening 2024-02-28 16:52:38 -05:00 committed by Stefan Miklosovic
parent 7fe30fc313
commit 67bbbb0125
No known key found for this signature in database
GPG Key ID: 32F35CB2F546D93E
6 changed files with 84 additions and 86 deletions

View File

@ -383,7 +383,8 @@ class Shell(cmd.Cmd):
if extra != -1:
baseversion = baseversion[0:extra]
if baseversion != build_version:
print("WARNING: cqlsh was built against {}, but this server is {}. All features may not work!".format(build_version, baseversion))
print("WARNING: cqlsh was built against {}, but this server is {}. All features may not work!"
.format(build_version, baseversion)) # ToDo: use file=sys.stderr)
@property
def batch_mode(self):

View File

@ -107,10 +107,6 @@ def timing_out(seconds):
signal.setitimer(signal.ITIMER_REAL, 0)
def noop(*a):
pass
class ProcRunner:
def __init__(self, path, tty=True, env=None, args=()):
self.exe_path = path
@ -124,7 +120,6 @@ class ProcRunner:
self.start_proc()
def start_proc(self):
preexec = noop
stdin = stdout = stderr = None
cqlshlog.info("Spawning %r subprocess with args: %r and env: %r"
% (self.exe_path, self.args, self.env))
@ -141,7 +136,6 @@ class ProcRunner:
self.read = self.read_tty
else:
stdin = stdout = subprocess.PIPE
stderr = subprocess.STDOUT
self.proc = subprocess.Popen((self.exe_path,) + tuple(self.args),
env=self.env, stdin=stdin, stdout=stdout,
stderr=stderr, bufsize=0, close_fds=False)
@ -178,7 +172,9 @@ class ProcRunner:
return buf
def read_until(self, until, blksize=4096, timeout=None,
flags=0, ptty_timeout=None, replace=[]):
flags=0, ptty_timeout=None, replace=None):
if replace is None:
replace = []
if not isinstance(until, Pattern):
until = re.compile(until, flags)

View File

@ -52,6 +52,7 @@ def _assert_auth_provider_matches(actual, klass, expected_props):
assert isinstance(actual, klass)
assert expected_props == vars(actual)
class CustomAuthProviderTest(unittest.TestCase):
def setUp(self):
@ -81,18 +82,18 @@ class CustomAuthProviderTest(unittest.TestCase):
def test_partial_property_example(self):
actual = load_auth_provider(construct_config_path('partial_example'))
_assert_auth_provider_matches(
actual,
NoUserNamePlainTextAuthProvider,
{"username": '',
"password": ''})
actual,
NoUserNamePlainTextAuthProvider,
{"username": '',
"password": ''})
def test_full_property_example(self):
actual = load_auth_provider(construct_config_path('full_plain_text_example'))
_assert_auth_provider_matches(
actual,
PlainTextAuthProvider,
{"username": 'user1',
"password": 'pass1'})
actual,
PlainTextAuthProvider,
{"username": 'user1',
"password": 'pass1'})
def test_empty_example(self):
actual = load_auth_provider(construct_config_path('empty_example'))
@ -102,10 +103,10 @@ class CustomAuthProviderTest(unittest.TestCase):
creds_file = construct_config_path('plain_text_full_creds')
actual = load_auth_provider(cred_file=creds_file)
_assert_auth_provider_matches(
actual,
PlainTextAuthProvider,
{"username": 'user2',
"password": 'pass2'})
actual,
PlainTextAuthProvider,
{"username": 'user2',
"password": 'pass2'})
def test_no_cqlshrc_file(self):
actual = load_auth_provider()
@ -126,11 +127,11 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file, 'user-from-legacy', 'pass-from-legacy')
_assert_auth_provider_matches(
actual,
ComplexTextAuthProvider,
{"username": 'user-from-legacy',
"password": 'pass-from-legacy',
"extra_flag": 'flag2'})
actual,
ComplexTextAuthProvider,
{"username": 'user-from-legacy',
"password": 'pass-from-legacy',
"extra_flag": 'flag2'})
def test_creds_example(self):
creds_file = construct_config_path('complex_auth_provider_creds')
@ -138,11 +139,11 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file)
_assert_auth_provider_matches(
actual,
ComplexTextAuthProvider,
{"username": 'user1',
"password": 'pass2',
"extra_flag": 'flag2'})
actual,
ComplexTextAuthProvider,
{"username": 'user1',
"password": 'pass2',
"extra_flag": 'flag2'})
def test_legacy_example_use_passed_username(self):
creds_file = construct_config_path('plain_text_partial_creds')
@ -150,10 +151,10 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file, 'user3')
_assert_auth_provider_matches(
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": 'pass2'})
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": 'pass2'})
def test_legacy_example_no_auth_provider_given(self):
cqlshrc = construct_config_path('empty_example')
@ -161,10 +162,10 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file, 'user3', 'pass3')
_assert_auth_provider_matches(
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": 'pass3'})
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": 'pass3'})
def test_shouldnt_pass_no_password_when_alt_auth_provider(self):
cqlshrc = construct_config_path('complex_auth_provider')
@ -172,11 +173,11 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file, 'user3')
_assert_auth_provider_matches(
actual,
ComplexTextAuthProvider,
{"username": 'user3',
"password": 'default_pass',
"extra_flag": 'flag1'})
actual,
ComplexTextAuthProvider,
{"username": 'user3',
"password": 'default_pass',
"extra_flag": 'flag1'})
def test_legacy_example_no_password(self):
cqlshrc = construct_config_path('plain_text_partial_example')
@ -184,7 +185,7 @@ class CustomAuthProviderTest(unittest.TestCase):
actual = load_auth_provider(cqlshrc, creds_file, 'user3')
_assert_auth_provider_matches(
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": None})
actual,
PlainTextAuthProvider,
{"username": 'user3',
"password": None})

View File

@ -44,7 +44,7 @@ class CopyTaskTest(unittest.TestCase):
Host('10.0.0.2', SimpleConvictionPolicy, 9000),
Host('10.0.0.3', SimpleConvictionPolicy, 9000),
Host('10.0.0.4', SimpleConvictionPolicy, 9000)
]
]
def mock_shell(self):
"""

View File

@ -100,7 +100,7 @@ class CqlshCompletionCase(BaseTestCase):
if split_completed_lines:
completed_lines = list(map(set, (completion_separation_re.split(line.strip())
for line in choice_lines)))
for line in choice_lines)))
if not completed_lines:
return set()
@ -493,8 +493,8 @@ class TestCqlshCompletion(CqlshCompletionCase):
'TOKEN(a) >= TOKEN(0) IF b CONTAINS '),
choices=['false', 'true', '<pgStringLiteral>',
'-', '<float>', 'TOKEN', '<identifier>',
'<uuid>', '{', '[', 'NULL','<quotedStringLiteral>',
'<blobLiteral>','<wholenumber>', 'KEY'])
'<uuid>', '{', '[', 'NULL', '<quotedStringLiteral>',
'<blobLiteral>', '<wholenumber>', 'KEY'])
self.trycompletions(('DELETE FROM twenty_rows_composite_table USING TIMESTAMP 0 WHERE '
'TOKEN(a) >= TOKEN(0) IF b < 0 '),
choices=['AND', ';'])
@ -508,7 +508,7 @@ class TestCqlshCompletion(CqlshCompletionCase):
def test_complete_in_begin_batch(self):
self.trycompletions('BEGIN ', choices=['BATCH', 'COUNTER', 'UNLOGGED'])
self.trycompletions('BEGIN BATCH ', choices=['DELETE', 'INSERT', 'UPDATE', 'USING'])
self.trycompletions('BEGIN BATCH INSERT ', immediate='INTO ' )
self.trycompletions('BEGIN BATCH INSERT ', immediate='INTO ')
def test_complete_in_create_keyspace(self):
self.trycompletions('create keyspace ', '', choices=('<identifier>', '<quotedName>', 'IF'))
@ -588,18 +588,18 @@ class TestCqlshCompletion(CqlshCompletionCase):
self.trycompletions('CREATE TYPE foo ', choices=['(', '.'])
def test_complete_in_drop_type(self):
self.trycompletions('DROP TYPE ', choices=['IF', 'system_views.', 'system_metrics.',
'tags', 'system_traces.', 'system_distributed.', 'system_cluster_metadata.',
'phone_number', 'quote_udt', 'band_info_type', 'address', 'system.', 'system_schema.',
'system_auth.', 'system_virtual_schema.', self.cqlsh.keyspace + '.'
])
self.trycompletions('DROP TYPE ',
choices=['IF', 'system_views.', 'system_metrics.',
'tags', 'system_traces.', 'system_distributed.', 'system_cluster_metadata.',
'phone_number', 'quote_udt', 'band_info_type', 'address', 'system.', 'system_schema.',
'system_auth.', 'system_virtual_schema.', self.cqlsh.keyspace + '.'])
def test_complete_in_create_trigger(self):
self.trycompletions('CREATE TRIGGER ', choices=['<identifier>', '<quotedName>', 'IF' ])
self.trycompletions('CREATE TRIGGER foo ', immediate='ON ' )
self.trycompletions('CREATE TRIGGER foo ON ', choices=['system.', 'system_auth.',
'system_distributed.', 'system_schema.', 'system_traces.', 'system_views.',
'system_virtual_schema.' ], other_choices_ok=True)
self.trycompletions('CREATE TRIGGER ', choices=['<identifier>', '<quotedName>', 'IF'])
self.trycompletions('CREATE TRIGGER foo ', immediate='ON ')
self.trycompletions('CREATE TRIGGER foo ON ', choices=['system.', 'system_auth.', 'system_distributed.',
'system_schema.', 'system_traces.', 'system_views.',
'system_virtual_schema.'], other_choices_ok=True)
def create_columnfamily_table_template(self, name):
"""Parameterized test for CREATE COLUMNFAMILY and CREATE TABLE. Since
@ -768,12 +768,12 @@ class TestCqlshCompletion(CqlshCompletionCase):
self.trycompletions('CREATE MAT', immediate='ERIALIZED VIEW ')
self.trycompletions('CREATE MATERIALIZED VIEW AS ', choices=['AS', 'SELECT'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * ', immediate='FROM ')
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers ', immediate = 'WHERE ')
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id ', immediate='IS NOT NULL ' )
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers ', immediate='WHERE ')
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id ', immediate='IS NOT NULL ')
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PR', immediate='IMARY KEY ( ')
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY (host_id) ', choices=[';','WITH'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY (a, b) ', choices=[';','WITH'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY ((a,b), c) ', choices=[';','WITH'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY (host_id) ', choices=[';', 'WITH'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY (a, b) ', choices=[';', 'WITH'])
self.trycompletions('CREATE MATERIALIZED VIEW AS SELECT * FROM system.peers WHERE host_id IS NOT NULL PRIMARY KEY ((a,b), c) ', choices=[';', 'WITH'])
def test_complete_in_create_table(self):
self.trycompletions('CREATE T', choices=['TRIGGER', 'TABLE', 'TYPE'])
@ -896,8 +896,8 @@ class TestCqlshCompletion(CqlshCompletionCase):
def test_complete_in_use(self):
self.trycompletions('US', immediate='E ')
self.trycompletions('USE ', choices=[self.cqlsh.keyspace, 'system', 'system_auth', 'system_metrics',
'system_distributed', 'system_schema', 'system_traces', 'system_views',
'system_virtual_schema', 'system_cluster_metadata' ])
'system_distributed', 'system_schema', 'system_traces', 'system_views',
'system_virtual_schema', 'system_cluster_metadata'])
def test_complete_in_create_index(self):
self.trycompletions('CREATE I', immediate='NDEX ')
@ -1033,9 +1033,9 @@ class TestCqlshCompletion(CqlshCompletionCase):
def test_complete_in_create_role(self):
self.trycompletions('CREATE ROLE ', choices=['<identifier>', 'IF', '<quotedName>'])
self.trycompletions('CREATE ROLE IF ', immediate='NOT EXISTS ');
self.trycompletions('CREATE ROLE IF ', immediate='NOT EXISTS ')
self.trycompletions('CREATE ROLE foo WITH ', choices=['ACCESS', 'HASHED', 'LOGIN', 'OPTIONS', 'PASSWORD', 'SUPERUSER'])
self.trycompletions('CREATE ROLE foo WITH HASHED ', immediate='PASSWORD = ');
self.trycompletions('CREATE ROLE foo WITH HASHED ', immediate='PASSWORD = ')
self.trycompletions('CREATE ROLE foo WITH ACCESS TO ', choices=['ALL', 'DATACENTERS'])
self.trycompletions('CREATE ROLE foo WITH ACCESS TO ALL ', immediate='DATACENTERS ')
self.trycompletions('CREATE ROLE foo WITH ACCESS FROM ', choices=['ALL', 'CIDRS'])
@ -1051,10 +1051,10 @@ class TestCqlshCompletion(CqlshCompletionCase):
def test_complete_in_drop_role(self):
self.trycompletions('DROP ROLE ', choices=['<identifier>', 'IF', '<quotedName>'])
def test_complete_in_list(self):
self.trycompletions('LIST ', choices=['ALL', 'AUTHORIZE', 'DESCRIBE', 'EXECUTE', 'ROLES', 'USERS', 'ALTER', 'CREATE', 'DROP', 'MODIFY', 'SELECT', 'UNMASK', 'SELECT_MASKED', 'SUPERUSERS'])
self.trycompletions('LIST ',
choices=['ALL', 'AUTHORIZE', 'DESCRIBE', 'EXECUTE', 'ROLES', 'USERS', 'ALTER',
'CREATE', 'DROP', 'MODIFY', 'SELECT', 'UNMASK', 'SELECT_MASKED', 'SUPERUSERS'])
# Non-CQL Shell Commands
@ -1062,8 +1062,8 @@ class TestCqlshCompletion(CqlshCompletionCase):
self.trycompletions('CAPTURE ', choices=['OFF', ';', '<enter>'], other_choices_ok=True)
def test_complete_in_paging(self):
self.trycompletions('PAGING ', choices=['ON', 'OFF', ';', '<enter>', '<wholenumber>' ] )
self.trycompletions('PAGING 50 ', choices=[';', '<enter>' ] )
self.trycompletions('PAGING ', choices=['ON', 'OFF', ';', '<enter>', '<wholenumber>'])
self.trycompletions('PAGING 50 ', choices=[';', '<enter>'])
def test_complete_in_serial(self):
self.trycompletions('SERIAL CONSISTENCY ', choices=[';', '<enter>', 'LOCAL_SERIAL', 'SERIAL'])

View File

@ -609,12 +609,12 @@ class TestCqlshOutput(BaseTestCase):
self.assertEqual(outputlines[start_index], 'use NONEXISTENTKEYSPACE;')
start_index = 1
self.assertTrue(outputlines[start_index+1].endswith('cqlsh:system> '))
self.assertTrue(outputlines[start_index + 1].endswith('cqlsh:system> '))
midline = ColoredText(outputlines[start_index])
self.assertEqual(midline.plain(),
'InvalidRequest: Error from server: code=2200 [Invalid query] message="Keyspace \'nonexistentkeyspace\' does not exist"')
self.assertColorFromTags(midline,
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR")
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR")
def test_describe_keyspace_output(self):
with cqlsh_testrun(tty=True, env=self.default_env) as c:
@ -799,12 +799,12 @@ class TestCqlshOutput(BaseTestCase):
with cqlsh_testrun(tty=True, env=self.default_env) as c:
output = c.cmd_and_response('show version;')
self.assertRegex(output,
r'^\[cqlsh \S+ \| Cassandra \S+ \| CQL spec \S+ \| Native protocol \S+\]$')
r'^\[cqlsh \S+ \| Cassandra \S+ \| CQL spec \S+ \| Native protocol \S+\]$')
output = c.cmd_and_response('show host;')
self.assertHasColors(output)
self.assertRegex(output, '^Connected to .* at %s:%d$'
% (re.escape(TEST_HOST), TEST_PORT))
% (re.escape(TEST_HOST), TEST_PORT))
def test_eof_prints_newline(self):
with cqlsh_testrun(tty=True, env=self.default_env) as c:
@ -972,13 +972,13 @@ class TestCqlshOutput(BaseTestCase):
query = "SELECT text_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "I'm newb")
query = "SELECT map_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "{1: 'I''m newb'}")
@ -988,21 +988,21 @@ class TestCqlshOutput(BaseTestCase):
# Sets
query = "SELECT set_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "{'I''m newb'}")
# Lists
query = "SELECT list_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "['I''m newb']")
# Tuples
query = "SELECT tuple_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "(1, 'I''m newb')")
@ -1011,6 +1011,6 @@ class TestCqlshOutput(BaseTestCase):
query = "SELECT udt_data FROM " + ks + ".escape_quotes;"
output, result = cqlsh_testcall(prompt=None, env=self.default_env,
tty=False, input=query)
tty=False, input=query)
self.assertEqual(0, result)
self.assertEqual(output.splitlines()[3].strip(), "{data: 'I''m newb'}")