query_test.py 8.2 KB
Newer Older
1 2 3 4
import pytest

import difflib
import os
5 6
import random
import string
7 8 9 10
import subprocess
import sys


11 12 13 14 15 16 17 18 19
SKIP_LIST = [
    # these couple of tests hangs everything
    "00600_replace_running_query",
    "00987_distributed_stack_overflow",

    # just fail
    "00505_secure",
    "00505_shard_secure",
    "00646_url_engine",
I
Ivan 已提交
20
    "00725_memory_tracking",  # BROKEN
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
    "00834_cancel_http_readonly_queries_on_client_close",
    "00933_test_fix_extra_seek_on_compressed_cache",
    "00965_logs_level_bugfix",
    "00965_send_logs_level_concurrent_queries",
    "00990_hasToken",
    "00990_metric_log_table_not_empty",
    "01014_lazy_database_concurrent_recreate_reattach_and_show_tables",
    "01018_Distributed__shard_num",
    "01018_ip_dictionary",
    "01050_clickhouse_dict_source_with_subquery",
    "01053_ssd_dictionary",
    "01054_cache_dictionary_overflow_cell",
    "01057_http_compression_prefer_brotli",
    "01080_check_for_error_incorrect_size_of_nested_column",
    "01083_expressions_in_engine_arguments",
36
    # "01086_odbc_roundtrip",
37 38
    "01088_benchmark_query_id",
    "01098_temporary_and_external_tables",
I
Ivan 已提交
39
    "01099_parallel_distributed_insert_select",
40 41 42
    "01103_check_cpu_instructions_at_startup",
    "01114_database_atomic",
    "01148_zookeeper_path_macros_unfolding",
I
Ivan 已提交
43
    "01181_db_atomic_drop_on_cluster",  # tcp port in reference
44 45 46
    "01280_ssd_complex_key_dictionary",
    "01293_client_interactive_vertical_multiline",  # expect-test
    "01293_client_interactive_vertical_singleline",  # expect-test
I
Ivan 已提交
47
    "01293_system_distribution_queue",  # FLAKY
48 49 50 51 52 53
    "01293_show_clusters",
    "01294_lazy_database_concurrent_recreate_reattach_and_show_tables",
    "01294_system_distributed_on_cluster",
    "01300_client_save_history_when_terminated",  # expect-test
    "01304_direct_io",
    "01306_benchmark_json",
I
Ivan 已提交
54
    "01035_lc_empty_part_bug",  # FLAKY
55 56 57 58 59 60 61 62 63 64 65 66 67
    "01320_create_sync_race_condition_zookeeper",
    "01355_CSV_input_format_allow_errors",
    "01370_client_autocomplete_word_break_characters",  # expect-test
    "01376_GROUP_BY_injective_elimination_dictGet",
    "01393_benchmark_secure_port",
    "01418_custom_settings",
    "01451_wrong_error_long_query",
    "01455_opentelemetry_distributed",
    "01473_event_time_microseconds",
    "01474_executable_dictionary",
    "01507_clickhouse_server_start_with_embedded_config",
    "01514_distributed_cancel_query_on_error",
    "01520_client_print_query_id",  # expect-test
I
Ivan 已提交
68
    "01526_client_start_and_exit",  # expect-test
69 70 71 72 73 74 75
    "01527_dist_sharding_key_dictGet_reload",
    "01545_url_file_format_settings",
    "01553_datetime64_comparison",
    "01555_system_distribution_queue_mask",
    "01558_ttest_scipy",
    "01561_mann_whitney_scipy",
    "01582_distinct_optimization",
I
Ivan 已提交
76
    "01599_multiline_input_and_singleline_comments",  # expect-test
77
    "01601_custom_tld",
I
Ivan 已提交
78 79 80
    "01610_client_spawn_editor",  # expect-test
    "01676_clickhouse_client_autocomplete",  # expect-test (partially)
    "01683_text_log_deadlock",  # secure tcp
81 82 83
]


I
Ivan 已提交
84
def check_result(result, error, return_code, reference, replace_map):
I
Ivan 已提交
85 86 87
    if replace_map:
        for old, new in replace_map.items():
            result = result.replace(old.encode('utf-8'), new.encode('utf-8'))
88

I
Ivan 已提交
89 90 91 92 93 94
    if return_code != 0:
        try:
            print(error.decode('utf-8'), file=sys.stderr)
        except UnicodeDecodeError:
            print(error.decode('latin1'), file=sys.stderr)  # encoding with 1 symbol per 1 byte, covering all values
        pytest.fail('Client died unexpectedly with code {code}'.format(code=return_code), pytrace=False)
95 96 97
    elif result != reference:
        pytest.fail("Query output doesn't match reference:{eol}{diff}".format(
                eol=os.linesep,
I
Ivan Lezhankin 已提交
98 99 100
                diff=os.linesep.join(l.strip() for l in difflib.unified_diff(reference.decode('utf-8').splitlines(),
                                                                             result.decode('utf-8').splitlines(),
                                                                             fromfile='expected', tofile='actual'))),
101 102 103
            pytrace=False)


I
Ivan 已提交
104
def run_client(bin_prefix, port, database, query, reference, replace_map=None):
I
Ivan 已提交
105
    # We can't use `text=True` since some tests may return binary data
I
Ivan 已提交
106
    client = subprocess.Popen([bin_prefix + '-client', '--port', str(port), '-d', database, '-m', '-n', '--testmode'],
I
Ivan 已提交
107 108 109 110 111 112 113
                              stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    result, error = client.communicate(query.encode('utf-8'))
    assert client.returncode is not None, "Client should exit after processing all queries"

    check_result(result, error, client.returncode, reference, replace_map)


I
Ivan 已提交
114
def run_shell(bin_prefix, server, database, path, reference, replace_map=None):
I
Ivan 已提交
115 116 117
    env = {
        'CLICKHOUSE_BINARY': bin_prefix,
        'CLICKHOUSE_DATABASE': database,
118 119
        'CLICKHOUSE_PORT_TCP': str(server.tcp_port),
        'CLICKHOUSE_PORT_TCP_SECURE': str(server.tcps_port),
I
Ivan 已提交
120
        'CLICKHOUSE_PORT_TCP_WITH_PROXY': str(server.proxy_port),
121 122 123 124
        'CLICKHOUSE_PORT_HTTP': str(server.http_port),
        'CLICKHOUSE_PORT_INTERSERVER': str(server.inter_port),
        'CLICKHOUSE_TMP': server.tmp_dir,
        'CLICKHOUSE_CONFIG_CLIENT': server.client_config
I
Ivan 已提交
125 126 127 128 129 130 131 132
    }
    shell = subprocess.Popen([path], env=env, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    result, error = shell.communicate()
    assert shell.returncode is not None, "Script should exit after executing all commands"

    check_result(result, error, shell.returncode, reference, replace_map)


133 134
def random_str(length=10):
    alphabet = string.ascii_lowercase + string.digits
I
Ivan 已提交
135
    random.seed(os.urandom(8))
136 137 138
    return ''.join(random.choice(alphabet) for _ in range(length))


I
Ivan 已提交
139
def test_sql_query(bin_prefix, sql_query, standalone_server):
140 141 142 143 144
    for test in SKIP_LIST:
        if test in sql_query:
            pytest.skip("Test matches skip-list: " + test)
            return

145 146 147 148 149 150 151 152 153 154
    tcp_port = standalone_server.tcp_port

    query_path = sql_query + ".sql"
    reference_path = sql_query + ".reference"

    if not os.path.exists(reference_path):
        pytest.skip('No .reference file found')

    with open(query_path, 'r') as file:
        query = file.read()
I
Ivan Lezhankin 已提交
155
    with open(reference_path, 'rb') as file:
156 157
        reference = file.read()

158
    random_name = 'test_{random}'.format(random=random_str())
I
Ivan 已提交
159 160 161
    run_client(bin_prefix, tcp_port, 'default', 'CREATE DATABASE {random};'.format(random=random_name), b'')

    run_client(bin_prefix, tcp_port, random_name, query, reference, {random_name: 'default'})
162

163
    query = "SELECT 'SHOW ORPHANED TABLES'; SELECT name FROM system.tables WHERE database != 'system' ORDER BY (database, name);"
I
Ivan 已提交
164
    run_client(bin_prefix, tcp_port, 'default', query, b'SHOW ORPHANED TABLES\n')
165

I
Ivan 已提交
166
    query = 'DROP DATABASE {random};'.format(random=random_name)
I
Ivan 已提交
167
    run_client(bin_prefix, tcp_port, 'default', query, b'')
I
Ivan 已提交
168 169

    query = "SELECT 'SHOW ORPHANED DATABASES'; SHOW DATABASES;"
I
Ivan 已提交
170
    run_client(bin_prefix, tcp_port, 'default', query, b'SHOW ORPHANED DATABASES\ndefault\nsystem\n')
I
Ivan 已提交
171 172 173


def test_shell_query(bin_prefix, shell_query, standalone_server):
174 175 176 177 178
    for test in SKIP_LIST:
        if test in shell_query:
            pytest.skip("Test matches skip-list: " + test)
            return

I
Ivan 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191
    tcp_port = standalone_server.tcp_port

    shell_path = shell_query + ".sh"
    reference_path = shell_query + ".reference"

    if not os.path.exists(reference_path):
        pytest.skip('No .reference file found')

    with open(reference_path, 'rb') as file:
        reference = file.read()

    random_name = 'test_{random}'.format(random=random_str())
    query = 'CREATE DATABASE {random};'.format(random=random_name)
I
Ivan 已提交
192
    run_client(bin_prefix, tcp_port, 'default', query, b'')
I
Ivan 已提交
193

194
    run_shell(bin_prefix, standalone_server, random_name, shell_path, reference, {random_name: 'default'})
I
Ivan 已提交
195 196

    query = "SELECT 'SHOW ORPHANED TABLES'; SELECT name FROM system.tables WHERE database != 'system' ORDER BY (database, name);"
I
Ivan 已提交
197
    run_client(bin_prefix, tcp_port, 'default', query, b'SHOW ORPHANED TABLES\n')
I
Ivan 已提交
198 199

    query = 'DROP DATABASE {random};'.format(random=random_name)
I
Ivan 已提交
200
    run_client(bin_prefix, tcp_port, 'default', query, b'')
201 202

    query = "SELECT 'SHOW ORPHANED DATABASES'; SHOW DATABASES;"
I
Ivan 已提交
203
    run_client(bin_prefix, tcp_port, 'default', query, b'SHOW ORPHANED DATABASES\ndefault\nsystem\n')