15 """Run interop (cross-language) tests in parallel."""
17 from __future__
import print_function
23 import multiprocessing
42 except ImportError
as e:
46 atexit.register(
lambda: subprocess.call([
'stty',
'echo']))
48 ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),
'../..'))
51 _DEFAULT_SERVER_PORT = 8080
53 _SKIP_CLIENT_COMPRESSION = [
54 'client_compressed_unary',
'client_compressed_streaming'
57 _SKIP_SERVER_COMPRESSION = [
58 'server_compressed_unary',
'server_compressed_streaming'
61 _SKIP_COMPRESSION = _SKIP_CLIENT_COMPRESSION + _SKIP_SERVER_COMPRESSION
64 'status_code_and_message',
'custom_metadata',
'unimplemented_method',
65 'unimplemented_service'
68 _SKIP_SPECIAL_STATUS_MESSAGE = [
'special_status_message']
70 _ORCA_TEST_CASES = [
'orca_per_rpc',
'orca_oob']
72 _GOOGLE_DEFAULT_CREDS_TEST_CASE =
'google_default_credentials'
74 _SKIP_GOOGLE_DEFAULT_CREDS = [
75 _GOOGLE_DEFAULT_CREDS_TEST_CASE,
78 _COMPUTE_ENGINE_CHANNEL_CREDS_TEST_CASE =
'compute_engine_channel_credentials'
80 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS = [
81 _COMPUTE_ENGINE_CHANNEL_CREDS_TEST_CASE,
84 _TEST_TIMEOUT = 3 * 60
88 _SKIP_DATA_FRAME_PADDING = [
'data_frame_padding']
91 _DOCKER_BUILD_XML_REPORT =
'interop_docker_build/sponge_log.xml'
92 _TESTS_XML_REPORT =
'interop_test/sponge_log.xml'
104 return [
'cmake/build/interop_client'] + args
107 return [
'cmake/build/http2_client'] + args
113 return [
'cmake/build/interop_server'] + args
119 return _SKIP_DATA_FRAME_PADDING + \
120 _SKIP_SPECIAL_STATUS_MESSAGE + \
121 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
125 return _ORCA_TEST_CASES
135 self.
server_cwd =
'../grpc-dotnet/output/InteropTestsWebsite'
142 return [
'dotnet',
'exec',
'InteropTestsClient.dll'] + args
145 return [
'dotnet',
'exec',
'InteropTestsWebsite.dll'] + args
151 return _SKIP_GOOGLE_DEFAULT_CREDS + \
152 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
156 return _ORCA_TEST_CASES
171 return [
'dart',
'bin/client.dart'] + args
177 return [
'dart',
'bin/server.dart'] + args
183 return _SKIP_COMPRESSION + \
184 _SKIP_SPECIAL_STATUS_MESSAGE + \
185 _SKIP_GOOGLE_DEFAULT_CREDS + \
186 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
190 return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE + _ORCA_TEST_CASES
205 return [
'./run-test-client.sh'] + args
209 './interop-testing/build/install/grpc-interop-testing/bin/http2-client'
216 return [
'./run-test-server.sh'] + args
227 return _SKIP_CLIENT_COMPRESSION + [
'server_compressed_streaming']
240 return [
'./run-test-client.sh',
'--use_okhttp=true'] + args
249 return _SKIP_DATA_FRAME_PADDING
259 self.
client_cwd =
'/go/src/google.golang.org/grpc/interop/client'
260 self.
server_cwd =
'/go/src/google.golang.org/grpc/interop/server'
261 self.
http2_cwd =
'/go/src/google.golang.org/grpc/interop/http2'
265 return [
'go',
'run',
'client.go'] + args
268 return [
'go',
'run',
'negative_http2_client.go'] + args
274 return [
'go',
'run',
'server.go'] + args
277 return {
'GO111MODULE':
'on'}
280 return _SKIP_COMPRESSION + \
284 return _SKIP_COMPRESSION + \
292 """Represents the HTTP/2 Interop Test server
294 This pretends to be a language in order to be built and run, but really it
303 return [
'python test/http2_test/http2_test_server.py']
312 return _TEST_CASES + \
313 _SKIP_DATA_FRAME_PADDING + \
314 _SKIP_SPECIAL_STATUS_MESSAGE + \
315 _SKIP_GOOGLE_DEFAULT_CREDS + \
316 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS
326 """Represents the HTTP/2 Interop Test
328 This pretends to be a language in order to be built and run, but really it
337 return [
'tools/http2_interop/http2_interop.test',
'-test.v'] + args
346 return _TEST_CASES + \
347 _SKIP_SPECIAL_STATUS_MESSAGE + \
348 _SKIP_GOOGLE_DEFAULT_CREDS + \
349 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS
367 'packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
368 'node',
'--require',
'./test/fixtures/native_native',
369 'test/interop/interop_client.js'
377 'packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
378 'node',
'--require',
'./test/fixtures/native_native',
379 'test/interop/interop_server.js'
386 return _SKIP_COMPRESSION + \
387 _SKIP_DATA_FRAME_PADDING + \
388 _SKIP_GOOGLE_DEFAULT_CREDS + \
389 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
393 return _SKIP_COMPRESSION + \
409 'packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
410 'node',
'--require',
'./test/fixtures/js_js',
411 'test/interop/interop_client.js'
421 return _SKIP_COMPRESSION + \
422 _SKIP_DATA_FRAME_PADDING + \
423 _SKIP_GOOGLE_DEFAULT_CREDS + \
424 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
428 return _ORCA_TEST_CASES
442 return [
'src/php/bin/interop_client.sh'] + args
448 return [
'src/php/bin/interop_server.sh'] + args
454 return _SKIP_SERVER_COMPRESSION + \
455 _SKIP_DATA_FRAME_PADDING + \
456 _SKIP_GOOGLE_DEFAULT_CREDS + \
457 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
461 return _SKIP_COMPRESSION + \
477 port = re.search(
'--server_port=(\d+)', arg)
479 portnum = port.group(1)
480 cmdline =
'pod install && xcodebuild -workspace Tests.xcworkspace -scheme InteropTestsLocalSSL -destination name="iPhone 6" HOST_PORT_LOCALSSL=localhost:%s test' % portnum
494 return _TEST_CASES[1:] + \
495 _SKIP_COMPRESSION + \
496 _SKIP_DATA_FRAME_PADDING + \
497 _SKIP_SPECIAL_STATUS_MESSAGE + \
498 _SKIP_GOOGLE_DEFAULT_CREDS + \
499 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
503 return _SKIP_COMPRESSION + \
519 'tools/run_tests/interop/with_rvm.sh',
'ruby',
520 'src/ruby/pb/test/client.rb'
528 'tools/run_tests/interop/with_rvm.sh',
'ruby',
529 'src/ruby/pb/test/server.rb'
536 return _SKIP_SERVER_COMPRESSION + \
537 _SKIP_DATA_FRAME_PADDING + \
538 _SKIP_SPECIAL_STATUS_MESSAGE + \
539 _SKIP_GOOGLE_DEFAULT_CREDS + \
540 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
544 return _SKIP_COMPRESSION + \
551 _PYTHON_BINARY =
'py39/bin/python'
564 _PYTHON_BINARY,
'src/python/grpcio_tests/setup.py',
'run_interop',
565 '--client',
'--args="{}"'.
format(
' '.join(args))
571 'src/python/grpcio_tests/tests/http2/negative_http2_client.py',
579 _PYTHON_BINARY,
'src/python/grpcio_tests/setup.py',
'run_interop',
580 '--server',
'--args="{}"'.
format(
' '.join(args))
585 'LD_LIBRARY_PATH':
'{}/libs/opt'.
format(DOCKER_WORKDIR_ROOT),
586 'PYTHONPATH':
'{}/src/python/gens'.
format(DOCKER_WORKDIR_ROOT)
590 return _SKIP_COMPRESSION + \
591 _SKIP_DATA_FRAME_PADDING + \
592 _SKIP_GOOGLE_DEFAULT_CREDS + \
593 _SKIP_COMPUTE_ENGINE_CHANNEL_CREDS + \
597 return _SKIP_COMPRESSION + \
614 _PYTHON_BINARY,
'src/python/grpcio_tests/setup.py',
'run_interop',
615 '--use-asyncio',
'--client',
'--args="{}"'.
format(
' '.join(args))
621 'src/python/grpcio_tests/tests/http2/negative_http2_client.py',
629 _PYTHON_BINARY,
'src/python/grpcio_tests/setup.py',
630 'py39/bin/python',
'src/python/grpcio_tests/setup.py',
631 '--args="{}"'.
format(
' '.join(args))
636 'LD_LIBRARY_PATH':
'{}/libs/opt'.
format(DOCKER_WORKDIR_ROOT),
637 'PYTHONPATH':
'{}/src/python/gens'.
format(DOCKER_WORKDIR_ROOT)
642 return _SKIP_COMPRESSION + \
643 _SKIP_DATA_FRAME_PADDING + \
645 [
'timeout_on_sleeping_server'] + \
650 return _TEST_CASES + \
652 _HTTP2_TEST_CASES + \
653 _HTTP2_SERVER_TEST_CASES
656 return 'pythonasyncio'
677 'c++',
'node',
'aspnetcore',
'java',
'go',
'ruby',
'python',
'dart',
678 'pythonasyncio',
'php7'
682 'large_unary',
'empty_unary',
'ping_pong',
'empty_stream',
683 'client_streaming',
'server_streaming',
'cancel_after_begin',
684 'cancel_after_first_response',
'timeout_on_sleeping_server',
685 'custom_metadata',
'status_code_and_message',
'unimplemented_method',
686 'client_compressed_unary',
'server_compressed_unary',
687 'client_compressed_streaming',
'server_compressed_streaming',
688 'unimplemented_service',
'special_status_message',
'orca_per_rpc',
693 'compute_engine_creds',
697 _GOOGLE_DEFAULT_CREDS_TEST_CASE,
698 _COMPUTE_ENGINE_CHANNEL_CREDS_TEST_CASE,
701 _HTTP2_TEST_CASES = [
'tls',
'framing']
703 _HTTP2_SERVER_TEST_CASES = [
704 'rst_after_header',
'rst_after_data',
'rst_during_data',
'goaway',
'ping',
705 'max_streams',
'data_frame_padding',
'no_df_padding_sanity_test'
708 _GRPC_CLIENT_TEST_CASES_FOR_HTTP2_SERVER_TEST_CASES = {
709 'data_frame_padding':
'large_unary',
710 'no_df_padding_sanity_test':
'large_unary'
713 _HTTP2_SERVER_TEST_CASES_THAT_USE_GRPC_CLIENTS = list(
714 _GRPC_CLIENT_TEST_CASES_FOR_HTTP2_SERVER_TEST_CASES.keys())
716 _LANGUAGES_WITH_HTTP2_CLIENTS_FOR_HTTP2_SERVER_TEST_CASES = [
717 'java',
'go',
'python',
'c++'
720 _LANGUAGES_FOR_ALTS_TEST_CASES = [
'java',
'go',
'c++',
'python']
722 _SERVERS_FOR_ALTS_TEST_CASES = [
'java',
'go',
'c++',
'python']
724 _TRANSPORT_SECURITY_OPTIONS = [
'tls',
'alts',
'insecure']
726 _CUSTOM_CREDENTIALS_TYPE_OPTIONS = [
727 'tls',
'google_default_credentials',
'compute_engine_channel_creds'
730 DOCKER_WORKDIR_ROOT =
'/var/local/git/grpc'
734 """Wraps given cmdline array to create 'docker run' cmdline from it."""
738 docker_cmdline = [
'docker',
'run',
'-i',
'--rm=true']
742 for k, v
in list(environ.items()):
743 docker_cmdline += [
'-e',
'%s=%s' % (k, v)]
746 workdir = DOCKER_WORKDIR_ROOT
748 workdir = os.path.join(workdir, cwd)
749 docker_cmdline += [
'-w', workdir]
751 docker_cmdline += docker_args + [image] + cmdline
752 return docker_cmdline
756 """Returns docker cmdline adjusted for manual invocation."""
758 for item
in docker_cmdline:
759 if item.startswith(
'--name='):
761 if item == docker_image:
762 item =
"$docker_image"
763 item = item.replace(
'"',
'\\"')
765 if any(character.isspace()
for character
in item):
766 item =
"\"%s\"" % item
767 print_cmdline.append(item)
768 return ' '.join(print_cmdline)
772 """Returns docker cmdline adjusted for manual invocation."""
774 with open(filename,
'w')
as logfile:
775 logfile.write(
'#!/bin/bash\n')
776 logfile.write(
'# DO NOT MODIFY\n')
778 '# This file is generated by run_interop_tests.py/create_testcases.sh\n'
780 logfile.writelines(
"%s\n" % line
for line
in cmdlog)
781 print(
'Command log written to file %s' % filename)
785 """Creates bash -c cmdline from args list."""
788 return [
'bash',
'-c',
' '.join(cmdline)]
792 """Returns True if given test requires access to compute engine creds."""
793 language =
str(language)
794 if test_case ==
'compute_engine_creds':
796 if test_case ==
'oauth2_auth_token' and language ==
'c++':
802 def auth_options(language, test_case, google_default_creds_use_key_file,
803 service_account_key_file, default_service_account):
804 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
806 language =
str(language)
810 oauth_scope_arg =
'--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
811 key_file_arg =
'--service_account_key_file=%s' % service_account_key_file
812 default_account_arg =
'--default_service_account=%s' % default_service_account
814 if test_case
in [
'jwt_token_creds',
'per_rpc_creds',
'oauth2_auth_token']:
816 'aspnetcore',
'node',
'php7',
'python',
'ruby',
'nodepurejs'
818 env[
'GOOGLE_APPLICATION_CREDENTIALS'] = service_account_key_file
820 cmdargs += [key_file_arg]
822 if test_case
in [
'per_rpc_creds',
'oauth2_auth_token']:
823 cmdargs += [oauth_scope_arg]
825 if test_case ==
'oauth2_auth_token' and language ==
'c++':
827 cmdargs += [default_account_arg]
829 if test_case ==
'compute_engine_creds':
830 cmdargs += [oauth_scope_arg, default_account_arg]
832 if test_case == _GOOGLE_DEFAULT_CREDS_TEST_CASE:
833 if google_default_creds_use_key_file:
834 env[
'GOOGLE_APPLICATION_CREDENTIALS'] = service_account_key_file
835 cmdargs += [default_account_arg]
837 if test_case == _COMPUTE_ENGINE_CHANNEL_CREDS_TEST_CASE:
838 cmdargs += [default_account_arg]
840 return (cmdargs, env)
844 if job._spec.container_name:
845 dockerjob.docker_kill(job._spec.container_name)
855 server_host_nickname,
857 google_default_creds_use_key_file,
861 service_account_key_file=None,
862 default_service_account=None,
863 transport_security='tls'):
864 """Creates jobspec for cloud-to-prod interop test"""
865 container_name =
None
867 '--server_host=%s' % server_host,
'--server_port=443',
868 '--test_case=%s' % test_case
870 if transport_security ==
'tls':
871 transport_security_options = [
'--use_tls=true']
872 elif transport_security ==
'google_default_credentials' and str(
873 language)
in [
'c++',
'go',
'java',
'javaokhttp']:
874 transport_security_options = [
875 '--custom_credentials_type=google_default_credentials'
877 elif transport_security ==
'compute_engine_channel_creds' and str(
878 language)
in [
'go',
'java',
'javaokhttp']:
879 transport_security_options = [
880 '--custom_credentials_type=compute_engine_channel_creds'
884 'Invalid transport security option %s in cloud_to_prod_jobspec. Lang: %s'
885 % (
str(language), transport_security))
887 cmdargs = cmdargs + transport_security_options
888 environ = dict(language.cloud_to_prod_env(), **language.global_env())
891 language, test_case, google_default_creds_use_key_file,
892 service_account_key_file, default_service_account)
893 cmdargs += auth_cmdargs
894 environ.update(auth_env)
896 cwd = language.client_cwd
899 container_name = dockerjob.random_name(
'interop_client_%s' %
906 docker_args=[
'--net=host',
907 '--name=%s' % container_name])
908 if manual_cmd_log
is not None:
909 if manual_cmd_log == []:
910 manual_cmd_log.append(
'echo "Testing ${docker_image:=%s}"' %
916 suite_name =
'cloud_to_prod_auth' if auth
else 'cloud_to_prod'
917 test_job = jobset.JobSpec(cmdline=cmdline,
920 shortname=
'%s:%s:%s:%s:%s' %
921 (suite_name, language, server_host_nickname,
922 test_case, transport_security),
923 timeout_seconds=_TEST_TIMEOUT,
924 flake_retries=4
if args.allow_flakes
else 0,
925 timeout_retries=2
if args.allow_flakes
else 0,
926 kill_handler=_job_kill_handler)
928 test_job.container_name = container_name
938 transport_security='tls',
939 manual_cmd_log=None):
940 """Creates jobspec for cloud-to-cloud interop test"""
941 interop_only_options = [
942 '--server_host_override=foo.test.google.fr',
943 '--use_test_ca=true',
945 if transport_security ==
'tls':
946 interop_only_options += [
'--use_tls=true']
947 elif transport_security ==
'alts':
948 interop_only_options += [
'--use_tls=false',
'--use_alts=true']
949 elif transport_security ==
'insecure':
950 interop_only_options += [
'--use_tls=false']
953 'Invalid transport security option %s in cloud_to_cloud_jobspec.' %
957 client_test_case = test_case
958 if test_case
in _HTTP2_SERVER_TEST_CASES_THAT_USE_GRPC_CLIENTS:
959 client_test_case = _GRPC_CLIENT_TEST_CASES_FOR_HTTP2_SERVER_TEST_CASES[
961 if client_test_case
in language.unimplemented_test_cases():
962 print(
'asking client %s to run unimplemented test case %s' %
963 (repr(language), client_test_case))
966 if test_case
in _ORCA_TEST_CASES:
967 interop_only_options += [
968 '--service_config_json=\'{"loadBalancingConfig":[{"test_backend_metrics_load_balancer":{}}]}\''
972 '--test_case=%s' % client_test_case,
973 '--server_host=%s' % server_host,
974 '--server_port=%s' % server_port,
977 if test_case
in _HTTP2_SERVER_TEST_CASES:
978 if test_case
in _HTTP2_SERVER_TEST_CASES_THAT_USE_GRPC_CLIENTS:
979 client_options = interop_only_options + common_options
980 cmdline =
bash_cmdline(language.client_cmd(client_options))
981 cwd = language.client_cwd
984 language.client_cmd_http2interop(common_options))
985 cwd = language.http2_cwd
988 language.client_cmd(common_options + interop_only_options))
989 cwd = language.client_cwd
991 environ = language.global_env()
992 if docker_image
and language.safename !=
'objc':
994 container_name = dockerjob.random_name(
'interop_client_%s' %
1001 docker_args=[
'--net=host',
1002 '--name=%s' % container_name])
1003 if manual_cmd_log
is not None:
1004 if manual_cmd_log == []:
1005 manual_cmd_log.append(
'echo "Testing ${docker_image:=%s}"' %
1010 test_job = jobset.JobSpec(
1014 shortname=
'cloud_to_cloud:%s:%s_server:%s:%s' %
1015 (language, server_name, test_case, transport_security),
1016 timeout_seconds=_TEST_TIMEOUT,
1017 flake_retries=4
if args.allow_flakes
else 0,
1018 timeout_retries=2
if args.allow_flakes
else 0,
1019 kill_handler=_job_kill_handler)
1021 test_job.container_name = container_name
1027 transport_security='tls',
1028 manual_cmd_log=None):
1029 """Create jobspec for running a server"""
1030 container_name = dockerjob.random_name(
'interop_server_%s' %
1032 server_cmd = [
'--port=%s' % _DEFAULT_SERVER_PORT]
1033 if transport_security ==
'tls':
1034 server_cmd += [
'--use_tls=true']
1035 elif transport_security ==
'alts':
1036 server_cmd += [
'--use_tls=false',
'--use_alts=true']
1037 elif transport_security ==
'insecure':
1038 server_cmd += [
'--use_tls=false']
1040 print(
'Invalid transport security option %s in server_jobspec.' %
1043 cmdline =
bash_cmdline(language.server_cmd(server_cmd))
1044 environ = language.global_env()
1045 docker_args = [
'--name=%s' % container_name]
1046 if language.safename ==
'http2':
1050 docker_args += list(
1051 itertools.chain.from_iterable(
1052 (
'-p',
str(_DEFAULT_SERVER_PORT + i))
1053 for i
in range(
len(_HTTP2_SERVER_TEST_CASES))))
1063 '--health-cmd=python test/http2_test/http2_server_health_check.py '
1064 '--server_host=%s --server_port=%d' %
1065 (
'localhost', _DEFAULT_SERVER_PORT),
1066 '--health-interval=1s',
1067 '--health-retries=5',
1068 '--health-timeout=10s',
1072 docker_args += [
'-p',
str(_DEFAULT_SERVER_PORT)]
1076 cwd=language.server_cwd,
1078 docker_args=docker_args)
1079 if manual_cmd_log
is not None:
1080 if manual_cmd_log == []:
1081 manual_cmd_log.append(
'echo "Testing ${docker_image:=%s}"' %
1083 manual_cmd_log.append(
manual_cmdline(docker_cmdline, docker_image))
1084 server_job = jobset.JobSpec(cmdline=docker_cmdline,
1086 shortname=
'interop_server_%s' % language,
1087 timeout_seconds=30 * 60)
1088 server_job.container_name = container_name
1093 """Creates jobspec for building interop docker image for a language"""
1095 tag =
'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
1097 'INTEROP_IMAGE': tag,
1098 'BASE_NAME':
'grpc_interop_%s' % language.safename
1100 build_job = jobset.JobSpec(
1101 cmdline=[
'tools/run_tests/dockerize/build_interop_image.sh'],
1103 shortname=
'build_docker_%s' % (language),
1104 timeout_seconds=30 * 60)
1110 match = re.search(
r'\{"cases[^\]]*\]\}', stdout)
1114 results = json.loads(match.group(0))
1119 for case
in results[
'cases']:
1120 if case.get(
'skipped',
False):
1123 if case.get(
'passed',
False):
1127 failed_cases.append(case.get(
'name',
"NONAME"))
1132 'failed_cases':
', '.join(failed_cases),
1133 'percent': 1.0 * passed / (passed + failed)
1140 'default':
'grpc-test.sandbox.googleapis.com',
1141 'gateway_v4':
'grpc-test4.sandbox.googleapis.com',
1144 argp = argparse.ArgumentParser(description=
'Run interop tests.')
1145 argp.add_argument(
'-l',
1147 choices=[
'all'] + sorted(_LANGUAGES),
1150 help=
'Clients to run. Objc client can be only run on OSX.')
1151 argp.add_argument(
'-j',
'--jobs', default=multiprocessing.cpu_count(), type=int)
1152 argp.add_argument(
'--cloud_to_prod',
1154 action=
'store_const',
1156 help=
'Run cloud_to_prod tests.')
1157 argp.add_argument(
'--cloud_to_prod_auth',
1159 action=
'store_const',
1161 help=
'Run cloud_to_prod_auth tests.')
1162 argp.add_argument(
'--google_default_creds_use_key_file',
1164 action=
'store_const',
1166 help=(
'Whether or not we should use a key file for the '
1167 'google_default_credentials test case, e.g. by '
1168 'setting env var GOOGLE_APPLICATION_CREDENTIALS.'))
1169 argp.add_argument(
'--prod_servers',
1170 choices=list(prod_servers.keys()),
1171 default=[
'default'],
1173 help=(
'The servers to run cloud_to_prod and '
1174 'cloud_to_prod_auth tests against.'))
1175 argp.add_argument(
'-s',
1177 choices=[
'all'] + sorted(_SERVERS),
1179 help=
'Run cloud_to_cloud servers in a separate docker ' +
1180 'image. Servers can only be started automatically if ' +
1181 '--use_docker option is enabled.',
1184 '--override_server',
1186 type=
lambda kv: kv.split(
'='),
1188 'Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
1192 '--service_account_key_file',
1194 help=
'The service account key file to use for some auth interop tests.',
1195 default=
'/root/service_account/grpc-testing-ebe7c1ac7381.json')
1197 '--default_service_account',
1199 help=
'Default GCE service account email to use for some auth interop tests.',
1200 default=
'830293263384-compute@developer.gserviceaccount.com')
1205 action=
'store_const',
1207 help=
'When set, indicates that the script is running on CI (= not locally).'
1209 argp.add_argument(
'-v',
1212 action=
'store_const',
1217 action=
'store_const',
1219 help=
'Run all the interop tests under docker. That provides ' +
1220 'additional isolation and prevents the need to install ' +
1221 'language specific prerequisites. Only available on Linux.')
1225 action=
'store_const',
1228 'Allow flaky tests to show as passing (re-runs failed tests up to five times)'
1230 argp.add_argument(
'--manual_run',
1232 action=
'store_const',
1234 help=
'Prepare things for running interop tests manually. ' +
1235 'Preserve docker images after building them and skip '
1236 'actually running the tests. Only print commands to run by ' +
1241 action=
'store_const',
1243 help=
'Enable HTTP/2 client edge case testing. (Bad client, good server)')
1245 '--http2_server_interop',
1247 action=
'store_const',
1250 'Enable HTTP/2 server edge case testing. (Includes positive and negative tests'
1252 argp.add_argument(
'--transport_security',
1253 choices=_TRANSPORT_SECURITY_OPTIONS,
1258 help=
'Which transport security mechanism to use.')
1260 '--custom_credentials_type',
1261 choices=_CUSTOM_CREDENTIALS_TYPE_OPTIONS,
1262 default=_CUSTOM_CREDENTIALS_TYPE_OPTIONS,
1265 'Credential types to test in the cloud_to_prod setup. Default is to test with all creds types possible.'
1268 '--skip_compute_engine_creds',
1270 action=
'store_const',
1272 help=
'Skip auth tests requiring access to compute engine credentials.')
1276 action=
'store_const',
1279 '(Deprecated, has no effect) Put reports into subdirectories to improve '
1280 'presentation of results by Internal CI.'))
1281 argp.add_argument(
'--bq_result_table',
1285 help=
'Upload test results to a specified BQ table.')
1286 args = argp.parse_args()
1288 servers =
set(s
for s
in itertools.chain.from_iterable(
1289 _SERVERS
if x ==
'all' else [x]
for x
in args.server))
1291 if args.transport_security ==
'alts':
1292 servers = servers.intersection(_SERVERS_FOR_ALTS_TEST_CASES)
1296 print(
'Seen --use_docker flag, will run interop tests under docker.')
1299 'IMPORTANT: The changes you are testing need to be locally committed'
1302 'because only the committed changes in the current branch will be')
1303 print(
'copied to the docker environment.')
1306 if args.manual_run
and not args.use_docker:
1307 print(
'--manual_run is only supported with --use_docker option enabled.')
1310 if not args.use_docker
and servers:
1312 'Running interop servers is only supported with --use_docker option enabled.'
1318 all_but_objc =
set(six.iterkeys(_LANGUAGES)) -
set([
'objc'])
1319 languages =
set(_LANGUAGES[l]
for l
in itertools.chain.from_iterable(
1320 all_but_objc
if x ==
'all' else [x]
for x
in args.language))
1322 if args.transport_security ==
'alts':
1323 alts_languages =
set(_LANGUAGES[l]
for l
in _LANGUAGES_FOR_ALTS_TEST_CASES)
1324 languages = languages.intersection(alts_languages)
1326 languages_http2_clients_for_http2_server_interop =
set()
1327 if args.http2_server_interop:
1328 languages_http2_clients_for_http2_server_interop =
set(
1330 for l
in _LANGUAGES_WITH_HTTP2_CLIENTS_FOR_HTTP2_SERVER_TEST_CASES
1331 if 'all' in args.language
or l
in args.language)
1334 http2InteropServer =
Http2Server()
if args.http2_server_interop
else None
1339 languages_to_build =
set(_LANGUAGES[k]
1340 for k
in set([
str(l)
for l
in languages] +
1341 [s
for s
in servers]))
1342 languages_to_build = languages_to_build | languages_http2_clients_for_http2_server_interop
1344 if args.http2_interop:
1345 languages_to_build.add(http2Interop)
1347 if args.http2_server_interop:
1348 languages_to_build.add(http2InteropServer)
1351 for l
in languages_to_build:
1352 if str(l) ==
'objc':
1356 docker_images[
str(l)] = job.tag
1357 build_jobs.append(job)
1360 jobset.message(
'START',
1361 'Building interop docker images.',
1364 print(
'Jobs to run: \n%s\n' %
'\n'.join(
str(j)
for j
in build_jobs))
1366 num_failures, build_resultset = jobset.run(build_jobs,
1367 newline_on_success=
True,
1370 report_utils.render_junit_xml_report(build_resultset,
1371 _DOCKER_BUILD_XML_REPORT)
1373 if num_failures == 0:
1374 jobset.message(
'SUCCESS',
1375 'All docker images built successfully.',
1378 jobset.message(
'FAILED',
1379 'Failed to build interop docker images.',
1381 for image
in six.itervalues(docker_images):
1382 dockerjob.remove_image(image, skip_nonexistent=
True)
1385 server_manual_cmd_log = []
if args.manual_run
else None
1386 client_manual_cmd_log = []
if args.manual_run
else None
1390 server_addresses = {}
1395 docker_images.get(lang),
1396 args.transport_security,
1397 manual_cmd_log=server_manual_cmd_log)
1398 if not args.manual_run:
1399 job = dockerjob.DockerJob(spec)
1400 server_jobs[lang] = job
1401 server_addresses[lang] = (
'localhost',
1402 job.mapped_port(_DEFAULT_SERVER_PORT))
1405 server_addresses[lang] = (
'localhost',
'${SERVER_PORT}')
1407 http2_server_job =
None
1408 if args.http2_server_interop:
1410 lang =
str(http2InteropServer)
1412 docker_images.get(lang),
1413 manual_cmd_log=server_manual_cmd_log)
1414 if not args.manual_run:
1415 http2_server_job = dockerjob.DockerJob(spec)
1416 server_jobs[lang] = http2_server_job
1419 server_addresses[lang] = (
'localhost',
'${SERVER_PORT}')
1422 if args.cloud_to_prod:
1423 if args.transport_security
not in [
'tls']:
1424 print(
'TLS is always enabled for cloud_to_prod scenarios.')
1425 for server_host_nickname
in args.prod_servers:
1426 for language
in languages:
1427 for test_case
in _TEST_CASES:
1428 if not test_case
in language.unimplemented_test_cases():
1429 if not test_case
in _SKIP_ADVANCED + _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE + _ORCA_TEST_CASES:
1430 for transport_security
in args.custom_credentials_type:
1432 if transport_security ==
'google_default_credentials' and str(
1434 'c++',
'go',
'java',
'javaokhttp'
1438 if transport_security ==
'compute_engine_channel_creds' and str(
1440 'go',
'java',
'javaokhttp'
1446 server_host_nickname,
1447 prod_servers[server_host_nickname],
1448 google_default_creds_use_key_file=args.
1449 google_default_creds_use_key_file,
1450 docker_image=docker_images.get(
1452 manual_cmd_log=client_manual_cmd_log,
1453 service_account_key_file=args.
1454 service_account_key_file,
1455 default_service_account=args.
1456 default_service_account,
1457 transport_security=transport_security)
1458 jobs.append(test_job)
1459 if args.http2_interop:
1460 for test_case
in _HTTP2_TEST_CASES:
1464 server_host_nickname,
1465 prod_servers[server_host_nickname],
1466 google_default_creds_use_key_file=args.
1467 google_default_creds_use_key_file,
1468 docker_image=docker_images.get(
str(http2Interop)),
1469 manual_cmd_log=client_manual_cmd_log,
1470 service_account_key_file=args.service_account_key_file,
1471 default_service_account=args.default_service_account,
1472 transport_security=args.transport_security)
1473 jobs.append(test_job)
1475 if args.cloud_to_prod_auth:
1476 if args.transport_security
not in [
'tls']:
1477 print(
'TLS is always enabled for cloud_to_prod scenarios.')
1478 for server_host_nickname
in args.prod_servers:
1479 for language
in languages:
1480 for test_case
in _AUTH_TEST_CASES:
1481 if (
not args.skip_compute_engine_creds
or
1483 language, test_case)):
1484 if not test_case
in language.unimplemented_test_cases():
1485 if test_case == _GOOGLE_DEFAULT_CREDS_TEST_CASE:
1486 transport_security =
'google_default_credentials'
1487 elif test_case == _COMPUTE_ENGINE_CHANNEL_CREDS_TEST_CASE:
1488 transport_security =
'compute_engine_channel_creds'
1490 transport_security =
'tls'
1491 if transport_security
not in args.custom_credentials_type:
1496 server_host_nickname,
1497 prod_servers[server_host_nickname],
1498 google_default_creds_use_key_file=args.
1499 google_default_creds_use_key_file,
1500 docker_image=docker_images.get(
str(language)),
1502 manual_cmd_log=client_manual_cmd_log,
1503 service_account_key_file=args.
1504 service_account_key_file,
1505 default_service_account=args.
1506 default_service_account,
1507 transport_security=transport_security)
1508 jobs.append(test_job)
1509 for server
in args.override_server:
1510 server_name = server[0]
1511 (server_host, server_port) = server[1].
split(
':')
1512 server_addresses[server_name] = (server_host, server_port)
1514 for server_name, server_address
in list(server_addresses.items()):
1515 (server_host, server_port) = server_address
1516 server_language = _LANGUAGES.get(server_name,
None)
1519 skip_server = server_language.unimplemented_test_cases_server()
1520 for language
in languages:
1521 for test_case
in _TEST_CASES:
1522 if not test_case
in language.unimplemented_test_cases():
1523 if not test_case
in skip_server:
1530 docker_image=docker_images.get(
str(language)),
1531 transport_security=args.transport_security,
1532 manual_cmd_log=client_manual_cmd_log)
1533 jobs.append(test_job)
1535 if args.http2_interop:
1536 for test_case
in _HTTP2_TEST_CASES:
1537 if server_name ==
"go":
1546 docker_image=docker_images.get(
str(http2Interop)),
1547 transport_security=args.transport_security,
1548 manual_cmd_log=client_manual_cmd_log)
1549 jobs.append(test_job)
1551 if args.http2_server_interop:
1552 if not args.manual_run:
1553 http2_server_job.wait_for_healthy(timeout_seconds=600)
1554 for language
in languages_http2_clients_for_http2_server_interop:
1555 for test_case
in set(_HTTP2_SERVER_TEST_CASES) -
set(
1556 _HTTP2_SERVER_TEST_CASES_THAT_USE_GRPC_CLIENTS):
1557 offset = sorted(_HTTP2_SERVER_TEST_CASES).
index(test_case)
1558 server_port = _DEFAULT_SERVER_PORT + offset
1559 if not args.manual_run:
1560 server_port = http2_server_job.mapped_port(server_port)
1564 str(http2InteropServer),
1567 docker_image=docker_images.get(
str(language)),
1568 manual_cmd_log=client_manual_cmd_log)
1569 jobs.append(test_job)
1570 for language
in languages:
1577 for test_case
in _HTTP2_SERVER_TEST_CASES_THAT_USE_GRPC_CLIENTS:
1578 if test_case
not in language.unimplemented_test_cases():
1579 offset = sorted(_HTTP2_SERVER_TEST_CASES).
index(test_case)
1580 server_port = _DEFAULT_SERVER_PORT + offset
1581 if not args.manual_run:
1582 server_port = http2_server_job.mapped_port(server_port)
1583 if args.transport_security !=
'insecure':
1585 (
'Creating grpc client to http2 server test case '
1586 'with insecure connection, even though '
1587 'args.transport_security is not insecure. Http2 '
1588 'test server only supports insecure connections.'))
1592 str(http2InteropServer),
1595 docker_image=docker_images.get(
str(language)),
1596 transport_security=
'insecure',
1597 manual_cmd_log=client_manual_cmd_log)
1598 jobs.append(test_job)
1601 print(
'No jobs to run.')
1602 for image
in six.itervalues(docker_images):
1603 dockerjob.remove_image(image, skip_nonexistent=
True)
1607 print(
'All tests will skipped --manual_run option is active.')
1610 print(
'Jobs to run: \n%s\n' %
'\n'.join(
str(job)
for job
in jobs))
1612 num_failures, resultset = jobset.run(jobs,
1613 newline_on_success=
True,
1615 skip_jobs=args.manual_run)
1616 if args.bq_result_table
and resultset:
1619 jobset.message(
'FAILED',
'Some tests failed', do_newline=
True)
1621 jobset.message(
'SUCCESS',
'All tests passed', do_newline=
True)
1626 report_utils.render_junit_xml_report(resultset, _TESTS_XML_REPORT)
1628 for name, job
in list(resultset.items()):
1632 http2_server_test_cases = (_HTTP2_SERVER_TEST_CASES
1633 if args.http2_server_interop
else [])
1641 for server, job
in list(server_jobs.items()):
1642 if not job.is_running():
1643 print(
'Server "%s" has exited prematurely.' % server)
1645 dockerjob.finish_jobs([j
for j
in six.itervalues(server_jobs)])
1647 for image
in six.itervalues(docker_images):
1648 if not args.manual_run:
1649 print(
'Removing docker image %s' % image)
1650 dockerjob.remove_image(image)
1652 print(
'Preserving docker image: %s' % image)