mirror of https://github.com/apache/cassandra
cqlsh: Add tests for INSERT, UPDATE tab completion
Patch by Jim Witschey; reviewed by Tyler Hobbs for CASSANDRA-9125
This commit is contained in:
parent
cb8cb5f99d
commit
879691dd35
|
|
@ -1,4 +1,5 @@
|
|||
2.1.5
|
||||
* cqlsh: Add tests for INSERT and UPDATE tab completion (CASSANDRA-9125)
|
||||
* cqlsh: quote column names when needed in COPY FROM inserts (CASSANDRA-9080)
|
||||
* Add generate-idea-files target to build.xml (CASSANDRA-9123)
|
||||
* Do not load read meter for offline operations (CASSANDRA-9082)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,61 @@ class CqlshCompletionCase(BaseTestCase):
|
|||
def tearDown(self):
|
||||
self.cqlsh_runner.__exit__(None, None, None)
|
||||
|
||||
def _trycompletions_inner(self, inputstring, immediate='', choices=(), other_choices_ok=False):
|
||||
def _get_completions(self, inputstring, split_completed_lines=True):
|
||||
"""
|
||||
Get results of tab completion in cqlsh. Returns a bare string if a
|
||||
string completes immediately. Otherwise, returns a set of all
|
||||
whitespace-separated tokens in the offered completions by default, or a
|
||||
list of the lines in the offered completions if split_completed_lines is
|
||||
False.
|
||||
"""
|
||||
self.cqlsh.send(inputstring)
|
||||
self.cqlsh.send(TAB)
|
||||
immediate = self.cqlsh.read_up_to_timeout(COMPLETION_RESPONSE_TIME)
|
||||
immediate = immediate.replace(' \b', '')
|
||||
self.assertEqual(immediate[:len(inputstring)], inputstring)
|
||||
immediate = immediate[len(inputstring):]
|
||||
immediate = immediate.replace(BEL, '')
|
||||
|
||||
if immediate:
|
||||
return immediate
|
||||
|
||||
self.cqlsh.send(TAB)
|
||||
choice_output = self.cqlsh.read_up_to_timeout(COMPLETION_RESPONSE_TIME)
|
||||
if choice_output == BEL:
|
||||
choice_output = ''
|
||||
|
||||
self.cqlsh.send(CTRL_C) # cancel any current line
|
||||
self.cqlsh.read_to_next_prompt()
|
||||
|
||||
choice_lines = choice_output.splitlines()
|
||||
if choice_lines:
|
||||
# ensure the last line of the completion is the prompt
|
||||
prompt_regex = self.cqlsh.prompt.lstrip() + re.escape(inputstring)
|
||||
msg = ('Double-tab completion '
|
||||
'does not print prompt for input "{}"'.format(inputstring))
|
||||
self.assertRegexpMatches(choice_lines[-1], prompt_regex, msg=msg)
|
||||
|
||||
choice_lines = [line.strip() for line in choice_lines[:-1]]
|
||||
choice_lines = [line for line in choice_lines if line]
|
||||
|
||||
if split_completed_lines:
|
||||
completed_lines = map(set, (completion_separation_re.split(line.strip())
|
||||
for line in choice_lines))
|
||||
|
||||
if not completed_lines:
|
||||
return set()
|
||||
|
||||
completed_tokens = set.union(*completed_lines)
|
||||
return completed_tokens - {''}
|
||||
else:
|
||||
return choice_lines
|
||||
|
||||
assert False
|
||||
|
||||
def _trycompletions_inner(self, inputstring, immediate='', choices=(),
|
||||
other_choices_ok=False,
|
||||
split_completed_lines=True):
|
||||
"""
|
||||
Test tab completion in cqlsh. Enters in the text in inputstring, then
|
||||
simulates a tab keypress to see what is immediately completed (this
|
||||
|
|
@ -53,37 +107,25 @@ class CqlshCompletionCase(BaseTestCase):
|
|||
is simulated in order to get a list of choices, which are expected to
|
||||
match the items in 'choices' (order is not important, but case is).
|
||||
"""
|
||||
self.cqlsh.send(inputstring)
|
||||
self.cqlsh.send(TAB)
|
||||
completed = self.cqlsh.read_up_to_timeout(COMPLETION_RESPONSE_TIME)
|
||||
completed = completed.replace(' \b', '')
|
||||
self.assertEqual(completed[:len(inputstring)], inputstring)
|
||||
completed = completed[len(inputstring):]
|
||||
completed = completed.replace(BEL, '')
|
||||
self.assertEqual(completed, immediate, 'cqlsh completed %r, but we expected %r'
|
||||
% (completed, immediate))
|
||||
completed = self._get_completions(inputstring,
|
||||
split_completed_lines=split_completed_lines)
|
||||
|
||||
if immediate:
|
||||
msg = 'cqlsh completed %r, but we expected %r' % (completed, immediate)
|
||||
self.assertEqual(completed, immediate, msg=msg)
|
||||
return
|
||||
|
||||
self.cqlsh.send(TAB)
|
||||
choice_output = self.cqlsh.read_up_to_timeout(COMPLETION_RESPONSE_TIME)
|
||||
if choice_output == BEL:
|
||||
lines = ()
|
||||
else:
|
||||
lines = choice_output.splitlines()
|
||||
self.assertRegexpMatches(lines[-1], self.cqlsh.prompt.lstrip() + re.escape(inputstring))
|
||||
choicesseen = set()
|
||||
for line in lines[:-1]:
|
||||
choicesseen.update(completion_separation_re.split(line.strip()))
|
||||
choicesseen.discard('')
|
||||
if other_choices_ok:
|
||||
self.assertEqual(set(choices), choicesseen.intersection(choices))
|
||||
self.assertEqual(set(choices), completed.intersection(choices))
|
||||
else:
|
||||
self.assertEqual(set(choices), choicesseen)
|
||||
self.assertEqual(set(choices), set(completed))
|
||||
|
||||
def trycompletions(self, inputstring, immediate='', choices=(), other_choices_ok=False):
|
||||
def trycompletions(self, inputstring, immediate='', choices=(),
|
||||
other_choices_ok=False, split_completed_lines=True):
|
||||
try:
|
||||
self._trycompletions_inner(inputstring, immediate, choices, other_choices_ok)
|
||||
self._trycompletions_inner(inputstring, immediate, choices,
|
||||
other_choices_ok=other_choices_ok,
|
||||
split_completed_lines=split_completed_lines)
|
||||
finally:
|
||||
self.cqlsh.send(CTRL_C) # cancel any current line
|
||||
self.cqlsh.read_to_next_prompt()
|
||||
|
|
@ -114,10 +156,213 @@ class TestCqlshCompletion(CqlshCompletionCase):
|
|||
pass
|
||||
|
||||
def test_complete_in_insert(self):
|
||||
pass
|
||||
self.trycompletions('INSERT INTO ',
|
||||
choices=('twenty_rows_table',
|
||||
'ascii_with_special_chars',
|
||||
'users',
|
||||
'has_all_types',
|
||||
'system.',
|
||||
'system_auth.',
|
||||
'empty_composite_table',
|
||||
'empty_table',
|
||||
'undefined_values_table',
|
||||
'dynamic_columns',
|
||||
'twenty_rows_composite_table',
|
||||
'utf8_with_special_chars',
|
||||
'system_traces.',
|
||||
'songs'),
|
||||
other_choices_ok=True)
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table',
|
||||
immediate=' ')
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table ',
|
||||
choices=['(', 'JSON'])
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table (a, b ',
|
||||
choices=(')', ','))
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table (a, b, ',
|
||||
immediate='c ')
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table (a, b, c ',
|
||||
choices=(',', ')'))
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table (a, b)',
|
||||
immediate=' VALUES ( ')
|
||||
self.trycompletions('INSERT INTO twenty_rows_composite_table (a, b, c) VAL',
|
||||
immediate='UES ( ')
|
||||
|
||||
self.trycompletions(
|
||||
'INSERT INTO twenty_rows_composite_table (a, b, c) VALUES (',
|
||||
['<value for a (text)>'],
|
||||
split_completed_lines=False)
|
||||
|
||||
self.trycompletions(
|
||||
"INSERT INTO twenty_rows_composite_table (a, b, c) VALUES ('",
|
||||
['<value for a (text)>'],
|
||||
split_completed_lines=False)
|
||||
|
||||
self.trycompletions(
|
||||
"INSERT INTO twenty_rows_composite_table (a, b, c) VALUES ( 'eggs",
|
||||
['<value for a (text)>'],
|
||||
split_completed_lines=False)
|
||||
|
||||
self.trycompletions(
|
||||
"INSERT INTO twenty_rows_composite_table (a, b, c) VALUES ('eggs'",
|
||||
immediate=', ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs',"),
|
||||
['<value for b (text)>'],
|
||||
split_completed_lines=False)
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam')"),
|
||||
immediate=' ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') "),
|
||||
choices=[';', 'USING', 'IF'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam');"),
|
||||
choices=['?', 'ALTER', 'BEGIN', 'CAPTURE', 'CONSISTENCY', 'COPY',
|
||||
'CREATE', 'DEBUG', 'DELETE', 'DESC', 'DESCRIBE', 'DROP',
|
||||
'EXPAND', 'GRANT', 'HELP', 'INSERT', 'LIST', 'PAGING',
|
||||
'REVOKE', 'SELECT', 'SHOW', 'SOURCE', 'TRACING',
|
||||
'TRUNCATE', 'UPDATE', 'USE', 'exit', 'quit'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') US"),
|
||||
immediate='ING T')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING"),
|
||||
immediate=' T')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING T"),
|
||||
choices=['TTL', 'TIMESTAMP'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TT"),
|
||||
immediate='L ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TI"),
|
||||
immediate='MESTAMP ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TIMESTAMP "),
|
||||
choices=['<wholenumber>'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL "),
|
||||
choices=['<wholenumber>'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TIMESTAMP 0 "),
|
||||
choices=['AND', ';'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL 0 "),
|
||||
choices=['AND', ';'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TIMESTAMP 0 A"),
|
||||
immediate='ND TTL ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL 0 A"),
|
||||
immediate='ND TIMESTAMP ')
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL 0 AND TIMESTAMP "),
|
||||
choices=['<wholenumber>'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL 0 AND TIMESTAMP 0 "),
|
||||
choices=['AND', ';'])
|
||||
|
||||
self.trycompletions(
|
||||
("INSERT INTO twenty_rows_composite_table (a, b, c) "
|
||||
"VALUES ( 'eggs', 'sausage', 'spam') USING TTL 0 AND TIMESTAMP 0 AND "),
|
||||
choices=[])
|
||||
|
||||
|
||||
def test_complete_in_update(self):
|
||||
pass
|
||||
self.trycompletions("UPD", immediate="ATE ")
|
||||
self.trycompletions("UPDATE ",
|
||||
choices=['twenty_rows_table', 'system_auth.',
|
||||
'users', 'has_all_types', 'system.',
|
||||
'ascii_with_special_chars',
|
||||
'empty_composite_table', 'empty_table',
|
||||
'undefined_values_table',
|
||||
'dynamic_columns',
|
||||
'twenty_rows_composite_table',
|
||||
'utf8_with_special_chars', 'ks.',
|
||||
'system_traces.', 'songs'],
|
||||
other_choices_ok=True)
|
||||
|
||||
self.trycompletions("UPDATE empty_table ", choices=['USING', 'SET'])
|
||||
|
||||
self.trycompletions("UPDATE empty_table S",
|
||||
immediate='ET lonelycol = ')
|
||||
self.trycompletions("UPDATE empty_table SET lon",
|
||||
immediate='elycol = ')
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol",
|
||||
immediate=' = ')
|
||||
|
||||
self.trycompletions("UPDATE empty_table U", immediate='SING T')
|
||||
self.trycompletions("UPDATE empty_table USING T",
|
||||
choices=["TTL", "TIMESTAMP"])
|
||||
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = ",
|
||||
choices=['<term (text)>'],
|
||||
split_completed_lines=False)
|
||||
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eg",
|
||||
choices=['<term (text)>'],
|
||||
split_completed_lines=False)
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs'",
|
||||
choices=[',', 'WHERE'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE ",
|
||||
choices=['TOKEN(', '<identifier>', '<quotedName>'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE ",
|
||||
choices=['TOKEN(', '<identifier>', '<quotedName>'])
|
||||
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE lonel",
|
||||
choices=['<quotedName>', '<identifier>'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE lonelykey ",
|
||||
choices=['=', '<=', '>=', '>', '<', 'CONTAINS', 'IN', '['])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE lonelykey = 0.0 ",
|
||||
choices=['AND', 'IF', ';'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE lonelykey = 0.0 AND ",
|
||||
choices=['TOKEN(', '<identifier>', '<quotedName>'])
|
||||
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE TOKEN(lonelykey ",
|
||||
choices=[',', ')'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE TOKEN(lonelykey) ",
|
||||
choices=['=', '<=', '>=', '<', '>'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE TOKEN(lonelykey) <= TOKEN(13) ",
|
||||
choices=[';', 'AND', 'IF'])
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE TOKEN(lonelykey) <= TOKEN(13) IF ",
|
||||
choices=['EXISTS', '<quotedName>', '<identifier>'])
|
||||
|
||||
self.trycompletions("UPDATE empty_table SET lonelycol = 'eggs' WHERE TOKEN(lonelykey) <= TOKEN(13) IF EXISTS ",
|
||||
choices=['>=', '!=', '<=', 'IN', '[', ';', '=', '<', '>'])
|
||||
|
||||
def test_complete_in_delete(self):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ CREATE TABLE has_all_types (
|
|||
bigintcol bigint,
|
||||
blobcol blob,
|
||||
booleancol boolean,
|
||||
datecol date,
|
||||
decimalcol decimal,
|
||||
doublecol double,
|
||||
floatcol float,
|
||||
textcol text,
|
||||
timecol time,
|
||||
timestampcol timestamp,
|
||||
uuidcol uuid,
|
||||
varcharcol varchar,
|
||||
|
|
@ -18,34 +16,34 @@ CREATE TABLE has_all_types (
|
|||
) WITH compression = {'sstable_compression':'LZ4Compressor'};
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (0, -12, 'abcdefg', 1234567890123456789, 0x000102030405fffefd, true,
|
||||
'2001-07-13', 19952.11882, 1.0, -2.1, 'Voilá!',
|
||||
'23:12:15.889445123', '2012-05-14 12:53:20+0000', bd1924e1-6af8-44ae-b5e1-f24131dbd460, '"', 10000000000000000000000000);
|
||||
19952.11882, 1.0, -2.1, 'Voilá!',
|
||||
'2012-05-14 12:53:20+0000', bd1924e1-6af8-44ae-b5e1-f24131dbd460, '"', 10000000000000000000000000);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (1, 2147483647, '__!''$#@!~"', 9223372036854775807, 0xffffffffffffffffff, true,
|
||||
'2012-11-30', 0.00000000000001, 9999999.999, 99999.99, '∭Ƕ⑮ฑ➳❏''',
|
||||
'00:01:59.998994', '1900-01-01+0000', ffffffff-ffff-ffff-ffff-ffffffffffff, 'newline->
|
||||
0.00000000000001, 9999999.999, 99999.99, '∭Ƕ⑮ฑ➳❏''',
|
||||
'1900-01-01+0000', ffffffff-ffff-ffff-ffff-ffffffffffff, 'newline->
|
||||
<-', 9);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (2, 0, '', 0, 0x, false,
|
||||
0, 0.0, 0.0, 0.0, '',
|
||||
'0:0:0.1', 0, 00000000-0000-0000-0000-000000000000, '', 0);
|
||||
0.0, 0.0, 0.0, '',
|
||||
0, 00000000-0000-0000-0000-000000000000, '', 0);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (3, -2147483648, '''''''', -9223372036854775808, 0x80, false,
|
||||
'9999-12-31', 10.0000000000000, -1004.10, 100000000.9, '龍馭鬱',
|
||||
'23:59:59.999999999', '2038-01-19T03:14-1200', ffffffff-ffff-1fff-8fff-ffffffffffff,
|
||||
'''', -10000000000000000000000000);
|
||||
10.0000000000000, -1004.10, 100000000.9, '龍馭鬱',
|
||||
'2038-01-19T03:14-1200', ffffffff-ffff-1fff-8fff-ffffffffffff,
|
||||
'''', -10000000000000000000000000);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
|
|
|
|||
Loading…
Reference in New Issue