Use pregenerated gRPC protocol pb2 files to fix test flakyness.

This commit is contained in:
Vitaly Baranov 2023-09-23 21:13:13 +02:00
parent cf33674738
commit d39bd7154f
22 changed files with 432 additions and 147 deletions

View File

@ -27,7 +27,7 @@ CONTAINER_NAME = f"{VOLUME_NAME}_{random_str()}"
CONFIG_DIR_IN_REPO = "programs/server"
INTEGRATION_DIR_IN_REPO = "tests/integration"
SRC_DIR_IN_REPO = "src"
UTILS_DIR_IN_REPO = "utils"
DIND_INTEGRATION_TESTS_IMAGE_NAME = "clickhouse/integration-tests-runner"
@ -89,12 +89,16 @@ def check_args_and_update_paths(args):
)
logging.info("Cases dir is not set. Will use %s" % (args.cases_dir))
if args.src_dir:
if not os.path.isabs(args.src_dir):
args.src_dir = os.path.abspath(os.path.join(CURRENT_WORK_DIR, args.src_dir))
if args.utils_dir:
if not os.path.isabs(args.utils_dir):
args.utils_dir = os.path.abspath(
os.path.join(CURRENT_WORK_DIR, args.utils_dir)
)
else:
args.src_dir = os.path.abspath(os.path.join(CLICKHOUSE_ROOT, SRC_DIR_IN_REPO))
logging.info("src dir is not set. Will use %s" % (args.src_dir))
args.utils_dir = os.path.abspath(
os.path.join(CLICKHOUSE_ROOT, UTILS_DIR_IN_REPO)
)
logging.info("utils dir is not set. Will use %s" % (args.utils_dir))
logging.info(
"base_configs_dir: {}, binary: {}, cases_dir: {} ".format(
@ -115,7 +119,7 @@ def check_args_and_update_paths(args):
if args.dockerd_volume:
if not os.path.isabs(args.dockerd_volume):
args.src_dir = os.path.abspath(
args.dockerd_volume = os.path.abspath(
os.path.join(CURRENT_WORK_DIR, args.dockerd_volume)
)
@ -197,9 +201,9 @@ if __name__ == "__main__":
)
parser.add_argument(
"--src-dir",
default=os.environ.get("CLICKHOUSE_SRC_DIR"),
help="Path to the 'src' directory in repository. Used to provide schemas (e.g. *.proto) for some tests when those schemas are located in the 'src' directory",
"--utils-dir",
default=os.environ.get("CLICKHOUSE_UTILS_DIR"),
help="Path to the 'utils' directory in repository. Used to provide Python modules for grpc protocol schemas which are located in the 'utils' directory",
)
parser.add_argument(
@ -424,7 +428,7 @@ if __name__ == "__main__":
f"--volume={args.library_bridge_binary}:/clickhouse-library-bridge "
f"--volume={args.base_configs_dir}:/clickhouse-config "
f"--volume={args.cases_dir}:/ClickHouse/tests/integration "
f"--volume={args.src_dir}/Server/grpc_protos:/ClickHouse/src/Server/grpc_protos "
f"--volume={args.utils_dir}/grpc-client/pb2:/ClickHouse/utils/grpc-client/pb2 "
f"--volume=/run:/run/host:ro {dockerd_internal_volume} {env_tags} {env_cleanup} "
f"-e DOCKER_CLIENT_TIMEOUT=300 -e COMPOSE_HTTP_TIMEOUT=600 {use_analyzer} -e PYTHONUNBUFFERED=1 "
f'-e PYTEST_ADDOPTS="{parallel_args} {pytest_opts} {tests_list} {rand_args} -vvv"'

View File

@ -0,0 +1 @@
../../../utils/grpc-client/pb2

View File

@ -1 +0,0 @@
../../../../src/Server/grpc_protos/clickhouse_grpc.proto

View File

@ -10,32 +10,20 @@ from threading import Thread
import gzip
import lz4.frame
script_dir = os.path.dirname(os.path.realpath(__file__))
pb2_dir = os.path.join(script_dir, "pb2")
if pb2_dir not in sys.path:
sys.path.append(pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute pb2/generate.py to generate these modules.
GRPC_PORT = 9100
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
DEFAULT_ENCODING = "utf-8"
# Use grpcio-tools to generate *pb2.py files from *.proto.
proto_dir = os.path.join(SCRIPT_DIR, "./protos")
gen_dir = os.path.join(SCRIPT_DIR, "./_gen")
os.makedirs(gen_dir, exist_ok=True)
run_and_check(
"python3 -m grpc_tools.protoc -I{proto_dir} --python_out={gen_dir} --grpc_python_out={gen_dir} \
{proto_dir}/clickhouse_grpc.proto".format(
proto_dir=proto_dir, gen_dir=gen_dir
),
shell=True,
)
sys.path.append(gen_dir)
import clickhouse_grpc_pb2
import clickhouse_grpc_pb2_grpc
# Utilities
config_dir = os.path.join(SCRIPT_DIR, "./configs")
config_dir = os.path.join(script_dir, "./configs")
cluster = ClickHouseCluster(__file__)
node = cluster.add_instance(
"node",

View File

@ -0,0 +1 @@
../../../utils/grpc-client/pb2

View File

@ -1 +0,0 @@
../../../../src/Server/grpc_protos/clickhouse_grpc.proto

View File

@ -4,35 +4,23 @@ import sys
import grpc
from helpers.cluster import ClickHouseCluster, run_and_check
script_dir = os.path.dirname(os.path.realpath(__file__))
pb2_dir = os.path.join(script_dir, "pb2")
if pb2_dir not in sys.path:
sys.path.append(pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute pb2/generate.py to generate these modules.
# The test cluster is configured with certificate for that host name, see 'server-ext.cnf'.
# The client have to verify server certificate against that name. Client uses SNI
SSL_HOST = "integration-tests.clickhouse.com"
GRPC_PORT = 9100
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
DEFAULT_ENCODING = "utf-8"
# Use grpcio-tools to generate *pb2.py files from *.proto.
proto_dir = os.path.join(SCRIPT_DIR, "./protos")
gen_dir = os.path.join(SCRIPT_DIR, "./_gen")
os.makedirs(gen_dir, exist_ok=True)
run_and_check(
"python3 -m grpc_tools.protoc -I{proto_dir} --python_out={gen_dir} --grpc_python_out={gen_dir} \
{proto_dir}/clickhouse_grpc.proto".format(
proto_dir=proto_dir, gen_dir=gen_dir
),
shell=True,
)
sys.path.append(gen_dir)
import clickhouse_grpc_pb2
import clickhouse_grpc_pb2_grpc
# Utilities
config_dir = os.path.join(SCRIPT_DIR, "./configs")
config_dir = os.path.join(script_dir, "./configs")
cluster = ClickHouseCluster(__file__)
node = cluster.add_instance(
"node",

View File

@ -0,0 +1 @@
../../../utils/grpc-client/pb2

View File

@ -1 +0,0 @@
../../../../src/Server/grpc_protos/clickhouse_grpc.proto

View File

@ -9,9 +9,15 @@ import threading
from helpers.cluster import ClickHouseCluster, run_and_check
from helpers.test_tools import assert_logs_contain_with_retry
from helpers.uclient import client, prompt
script_dir = os.path.dirname(os.path.realpath(__file__))
grpc_protocol_pb2_dir = os.path.join(script_dir, "grpc_protocol_pb2")
if grpc_protocol_pb2_dir not in sys.path:
sys.path.append(grpc_protocol_pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute grpc_protocol_pb2/generate.py to generate these modules.
MAX_SESSIONS_FOR_USER = 2
POSTGRES_SERVER_PORT = 5433
MYSQL_SERVER_PORT = 9001
@ -20,22 +26,8 @@ GRPC_PORT = 9100
TEST_USER = "test_user"
TEST_PASSWORD = "123"
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
DEFAULT_ENCODING = "utf-8"
# Use grpcio-tools to generate *pb2.py files from *.proto.
proto_dir = os.path.join(SCRIPT_DIR, "./protos")
gen_dir = os.path.join(SCRIPT_DIR, "./_gen")
os.makedirs(gen_dir, exist_ok=True)
run_and_check(
f"python3 -m grpc_tools.protoc -I{proto_dir} --python_out={gen_dir} --grpc_python_out={gen_dir} {proto_dir}/clickhouse_grpc.proto",
shell=True,
)
sys.path.append(gen_dir)
import clickhouse_grpc_pb2
import clickhouse_grpc_pb2_grpc
cluster = ClickHouseCluster(__file__)
instance = cluster.add_instance(

View File

@ -0,0 +1 @@
../../../utils/grpc-client/pb2

View File

@ -1 +0,0 @@
../../../../src/Server/grpc_protos/clickhouse_grpc.proto

View File

@ -22,6 +22,13 @@ from pathlib import Path
from requests.exceptions import ConnectionError
from urllib3.util.retry import Retry
script_dir = os.path.dirname(os.path.realpath(__file__))
grpc_protocol_pb2_dir = os.path.join(script_dir, "grpc_protocol_pb2")
if grpc_protocol_pb2_dir not in sys.path:
sys.path.append(grpc_protocol_pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute grpc_protocol_pb2/generate.py to generate these modules.
cluster = ClickHouseCluster(__file__)
instance = cluster.add_instance(
"instance",
@ -44,22 +51,6 @@ instance = cluster.add_instance(
LOADS_QUERY = "SELECT value FROM system.events WHERE event = 'MainConfigLoads'"
# Use grpcio-tools to generate *pb2.py files from *.proto.
proto_dir = Path(__file__).parent / "protos"
gen_dir = Path(__file__).parent / "_gen"
gen_dir.mkdir(exist_ok=True)
run_and_check(
f"python3 -m grpc_tools.protoc -I{proto_dir!s} --python_out={gen_dir!s} --grpc_python_out={gen_dir!s} \
{proto_dir!s}/clickhouse_grpc.proto",
shell=True,
)
sys.path.append(str(gen_dir))
import clickhouse_grpc_pb2
import clickhouse_grpc_pb2_grpc
@pytest.fixture(name="cluster", scope="module")
def fixture_cluster():
try:

View File

@ -0,0 +1 @@
../../../utils/grpc-client/pb2

View File

@ -1 +0,0 @@
../../../../src/Server/grpc_protos/clickhouse_grpc.proto

View File

@ -8,27 +8,19 @@ import threading
from helpers.cluster import ClickHouseCluster, run_and_check
script_dir = os.path.dirname(os.path.realpath(__file__))
grpc_protocol_pb2_dir = os.path.join(script_dir, "grpc_protocol_pb2")
if grpc_protocol_pb2_dir not in sys.path:
sys.path.append(grpc_protocol_pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute grpc_protocol_pb2/generate.py to generate these modules.
POSTGRES_SERVER_PORT = 5433
MYSQL_SERVER_PORT = 9001
GRPC_PORT = 9100
SESSION_LOG_MATCHING_FIELDS = "auth_id, auth_type, client_version_major, client_version_minor, client_version_patch, interface"
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
DEFAULT_ENCODING = "utf-8"
# Use grpcio-tools to generate *pb2.py files from *.proto.
proto_dir = os.path.join(SCRIPT_DIR, "./protos")
gen_dir = os.path.join(SCRIPT_DIR, "./_gen")
os.makedirs(gen_dir, exist_ok=True)
run_and_check(
f"python3 -m grpc_tools.protoc -I{proto_dir} --python_out={gen_dir} --grpc_python_out={gen_dir} {proto_dir}/clickhouse_grpc.proto",
shell=True,
)
sys.path.append(gen_dir)
import clickhouse_grpc_pb2
import clickhouse_grpc_pb2_grpc
cluster = ClickHouseCluster(__file__)
instance = cluster.add_instance(

View File

@ -13,10 +13,14 @@ tmp=$(mktemp)
find_cmd=(
find "$GIT_ROOT" -type f -not -path "${GIT_ROOT}contrib/*"
\(
-name '*.py' -or -name "*.python" -or
\(
-executable -not -name "*.*" -exec sh -c 'file {} | grep -q "Python script"' \;
\)
\(
-name '*.py' -or -name "*.python" -or
\(
-executable -not -name "*.*" -exec sh -c 'file {} | grep -q "Python script"' \;
\)
\)
# We skip modules generated by the protocol buffer compiler from *.proto files.
-and -not -name '*_pb2.py' -and -not -name '*_pb2_grpc.py'
\)
)

View File

@ -10,10 +10,6 @@
# Most of the command line options are the same, for more information type
# ./clickhouse_grpc_client.py --help
import grpc # pip3 install grpcio
import grpc_tools # pip3 install grpcio-tools
import argparse, cmd, os, signal, subprocess, sys, threading, time, uuid
DEFAULT_HOST = "localhost"
DEFAULT_PORT = 9100
DEFAULT_USER_NAME = "default"
@ -24,6 +20,16 @@ STDIN_BUFFER_SIZE = 1048576
DEFAULT_ENCODING = "utf-8"
import grpc # pip3 install grpcio
import argparse, cmd, os, signal, sys, threading, time, uuid
script_dir = os.path.dirname(os.path.realpath(__file__))
pb2_dir = os.path.join(script_dir, "pb2")
if pb2_dir not in sys.path:
sys.path.append(pb2_dir)
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc # Execute pb2/generate.py to generate these modules.
class ClickHouseGRPCError(Exception):
pass
@ -80,8 +86,6 @@ class ClickHouseGRPCClient(cmd.Cmd):
self.session_id = None
def __enter__(self):
ClickHouseGRPCClient.__generate_pb2()
ClickHouseGRPCClient.__import_pb2()
self.__connect()
return self
@ -229,40 +233,6 @@ class ClickHouseGRPCClient(cmd.Cmd):
if result.HasField("exception"):
raise ClickHouseGRPCError(result.exception.display_text)
# Use grpcio-tools to generate *pb2.py files from *.proto.
@staticmethod
def __generate_pb2():
script_dir = os.path.dirname(os.path.realpath(__file__))
proto_dir = os.path.join(script_dir, "./protos")
gen_dir = os.path.join(script_dir, "./_gen")
if os.path.exists(os.path.join(gen_dir, "clickhouse_grpc_pb2_grpc.py")):
return
os.makedirs(gen_dir, exist_ok=True)
cmd = [
"python3",
"-m",
"grpc_tools.protoc",
"-I" + proto_dir,
"--python_out=" + gen_dir,
"--grpc_python_out=" + gen_dir,
proto_dir + "/clickhouse_grpc.proto",
]
p = subprocess.Popen(cmd, stderr=subprocess.PIPE)
# We don't want to show grpc_tools warnings.
errors = p.stderr.read().decode().strip("\n").split("\n")
only_warnings = all(("Warning" in error) for error in errors)
if not only_warnings:
error_print("\n".join(errors))
# Import the generated *pb2.py files.
@staticmethod
def __import_pb2():
script_dir = os.path.dirname(os.path.realpath(__file__))
gen_dir = os.path.join(script_dir, "./_gen")
sys.path.append(gen_dir)
global clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc
import clickhouse_grpc_pb2, clickhouse_grpc_pb2_grpc
# Prints only if interactive mode is activated.
def verbatim_print(self, *args, **kwargs):
if self.verbatim:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,165 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import clickhouse_grpc_pb2 as clickhouse__grpc__pb2
class ClickHouseStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.ExecuteQuery = channel.unary_unary(
'/clickhouse.grpc.ClickHouse/ExecuteQuery',
request_serializer=clickhouse__grpc__pb2.QueryInfo.SerializeToString,
response_deserializer=clickhouse__grpc__pb2.Result.FromString,
)
self.ExecuteQueryWithStreamInput = channel.stream_unary(
'/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamInput',
request_serializer=clickhouse__grpc__pb2.QueryInfo.SerializeToString,
response_deserializer=clickhouse__grpc__pb2.Result.FromString,
)
self.ExecuteQueryWithStreamOutput = channel.unary_stream(
'/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamOutput',
request_serializer=clickhouse__grpc__pb2.QueryInfo.SerializeToString,
response_deserializer=clickhouse__grpc__pb2.Result.FromString,
)
self.ExecuteQueryWithStreamIO = channel.stream_stream(
'/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamIO',
request_serializer=clickhouse__grpc__pb2.QueryInfo.SerializeToString,
response_deserializer=clickhouse__grpc__pb2.Result.FromString,
)
class ClickHouseServicer(object):
"""Missing associated documentation comment in .proto file."""
def ExecuteQuery(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ExecuteQueryWithStreamInput(self, request_iterator, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ExecuteQueryWithStreamOutput(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ExecuteQueryWithStreamIO(self, request_iterator, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_ClickHouseServicer_to_server(servicer, server):
rpc_method_handlers = {
'ExecuteQuery': grpc.unary_unary_rpc_method_handler(
servicer.ExecuteQuery,
request_deserializer=clickhouse__grpc__pb2.QueryInfo.FromString,
response_serializer=clickhouse__grpc__pb2.Result.SerializeToString,
),
'ExecuteQueryWithStreamInput': grpc.stream_unary_rpc_method_handler(
servicer.ExecuteQueryWithStreamInput,
request_deserializer=clickhouse__grpc__pb2.QueryInfo.FromString,
response_serializer=clickhouse__grpc__pb2.Result.SerializeToString,
),
'ExecuteQueryWithStreamOutput': grpc.unary_stream_rpc_method_handler(
servicer.ExecuteQueryWithStreamOutput,
request_deserializer=clickhouse__grpc__pb2.QueryInfo.FromString,
response_serializer=clickhouse__grpc__pb2.Result.SerializeToString,
),
'ExecuteQueryWithStreamIO': grpc.stream_stream_rpc_method_handler(
servicer.ExecuteQueryWithStreamIO,
request_deserializer=clickhouse__grpc__pb2.QueryInfo.FromString,
response_serializer=clickhouse__grpc__pb2.Result.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'clickhouse.grpc.ClickHouse', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class ClickHouse(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def ExecuteQuery(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/clickhouse.grpc.ClickHouse/ExecuteQuery',
clickhouse__grpc__pb2.QueryInfo.SerializeToString,
clickhouse__grpc__pb2.Result.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def ExecuteQueryWithStreamInput(request_iterator,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.stream_unary(request_iterator, target, '/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamInput',
clickhouse__grpc__pb2.QueryInfo.SerializeToString,
clickhouse__grpc__pb2.Result.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def ExecuteQueryWithStreamOutput(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_stream(request, target, '/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamOutput',
clickhouse__grpc__pb2.QueryInfo.SerializeToString,
clickhouse__grpc__pb2.Result.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def ExecuteQueryWithStreamIO(request_iterator,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.stream_stream(request_iterator, target, '/clickhouse.grpc.ClickHouse/ExecuteQueryWithStreamIO',
clickhouse__grpc__pb2.QueryInfo.SerializeToString,
clickhouse__grpc__pb2.Result.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

View File

@ -0,0 +1,29 @@
#!/usr/bin/env python3
import grpc_tools # pip3 install grpcio-tools
import os
import subprocess
script_dir = os.path.dirname(os.path.realpath(__file__))
dest_dir = script_dir
src_dir = os.path.abspath(os.path.join(script_dir, "../../../src/Server/grpc_protos"))
src_filename = "clickhouse_grpc.proto"
def generate():
cmd = [
"python3",
"-m",
"grpc_tools.protoc",
"-I" + src_dir,
"--python_out=" + dest_dir,
"--grpc_python_out=" + dest_dir,
os.path.join(src_dir, src_filename),
]
subprocess.run(cmd)
if __name__ == "__main__":
generate()

View File

@ -1 +0,0 @@
../../../src/Server/grpc_protos/clickhouse_grpc.proto