blob: 4a670e0c9db7e55112589b5a22c80e3ac3a1696c [file] [log] [blame]
Nathaniel Manistacbf21da2016-02-02 22:17:44 +00001#!/usr/bin/env python2.7
murgatroid9940809212016-01-13 17:45:30 -08002# Copyright 2015-2016, Google Inc.
Jan Tattermusch320bd612015-09-15 12:44:35 -07003# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Run interop (cross-language) tests in parallel."""
32
33import argparse
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -080034import atexit
Jan Tattermusch91ad0182015-10-01 09:22:03 -070035import dockerjob
Jan Tattermusch320bd612015-09-15 12:44:35 -070036import itertools
Jan Tattermusch320bd612015-09-15 12:44:35 -070037import jobset
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -080038import json
Jan Tattermusch210a0ea2015-10-02 15:05:36 -070039import multiprocessing
Jan Tattermusch8266c672015-09-17 09:18:03 -070040import os
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -080041import re
Adele Zhoua30f8292015-11-02 13:15:46 -080042import report_utils
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -080043import subprocess
Jan Tattermusch8266c672015-09-17 09:18:03 -070044import sys
Jan Tattermusch91ad0182015-10-01 09:22:03 -070045import tempfile
Jan Tattermusch8266c672015-09-17 09:18:03 -070046import time
Jan Tattermusch91ad0182015-10-01 09:22:03 -070047import uuid
Jan Tattermusch320bd612015-09-15 12:44:35 -070048
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -080049# Docker doesn't clean up after itself, so we do it on exit.
50atexit.register(lambda: subprocess.call(['stty', 'echo']))
51
Jan Tattermusch91ad0182015-10-01 09:22:03 -070052ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
53os.chdir(ROOT)
54
55_DEFAULT_SERVER_PORT=8080
Jan Tattermuschf49936a2015-09-16 15:44:26 -070056
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080057_SKIP_COMPRESSION = ['large_compressed_unary',
58 'server_compressed_streaming']
59
60_SKIP_ADVANCED = ['custom_metadata', 'status_code_and_message',
61 'unimplemented_method']
Jan Tattermusch8266c672015-09-17 09:18:03 -070062
Jan Tattermuschf49936a2015-09-16 15:44:26 -070063class CXXLanguage:
64
65 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -070066 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -070067 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -070068 self.safename = 'cxx'
Jan Tattermuschf49936a2015-09-16 15:44:26 -070069
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070070 def client_cmd(self, args):
71 return ['bins/opt/interop_client'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -070072
Jan Tattermuschf49936a2015-09-16 15:44:26 -070073 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -070074 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -070075
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070076 def server_cmd(self, args):
77 return ['bins/opt/interop_server', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -070078
Masood Malekghassemi18cc8422015-10-09 17:55:45 -070079 def global_env(self):
80 return {}
81
Jan Tattermusch289b7b92015-10-21 18:09:59 -070082 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080083 return _SKIP_ADVANCED + _SKIP_COMPRESSION
84
85 def unimplemented_test_cases_server(self):
86 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -070087
Jan Tattermuschf49936a2015-09-16 15:44:26 -070088 def __str__(self):
89 return 'c++'
90
91
92class CSharpLanguage:
93
94 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -070095 self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug'
Jan Tattermusch91ad0182015-10-01 09:22:03 -070096 self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
Jan Tattermusch0a14f622015-10-09 14:34:29 -070097 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -070098
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070099 def client_cmd(self, args):
100 return ['mono', 'Grpc.IntegrationTesting.Client.exe'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700101
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700102 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800103 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700104
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700105 def server_cmd(self, args):
106 return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700107
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700108 def global_env(self):
109 return {}
110
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700111 def unimplemented_test_cases(self):
Jan Tattermuscha86b41e2015-12-10 08:00:28 -0800112 # TODO: status_code_and_message doesn't work against node_server
113 return _SKIP_COMPRESSION + ['status_code_and_message']
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800114
115 def unimplemented_test_cases_server(self):
116 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700117
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700118 def __str__(self):
119 return 'csharp'
120
121
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700122class JavaLanguage:
123
124 def __init__(self):
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700125 self.client_cwd = '../grpc-java'
126 self.server_cwd = '../grpc-java'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700127 self.safename = str(self)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700128
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700129 def client_cmd(self, args):
130 return ['./run-test-client.sh'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700131
132 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700133 return {}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700134
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700135 def server_cmd(self, args):
136 return ['./run-test-server.sh', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700137
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700138 def global_env(self):
139 return {}
140
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700141 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800142 return _SKIP_ADVANCED + _SKIP_COMPRESSION
143
144 def unimplemented_test_cases_server(self):
145 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700146
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700147 def __str__(self):
148 return 'java'
149
150
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700151class GoLanguage:
152
153 def __init__(self):
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700154 # TODO: this relies on running inside docker
155 self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
156 self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700157 self.safename = str(self)
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700158
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700159 def client_cmd(self, args):
160 return ['go', 'run', 'client.go'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700161
162 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700163 return {}
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700164
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700165 def server_cmd(self, args):
166 return ['go', 'run', 'server.go', '--use_tls=true'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700167
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700168 def global_env(self):
169 return {}
170
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700171 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800172 return _SKIP_ADVANCED + _SKIP_COMPRESSION
173
174 def unimplemented_test_cases_server(self):
175 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700176
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700177 def __str__(self):
178 return 'go'
179
180
Carl Mastrangelode449102015-10-28 11:05:49 -0700181class Http2Client:
182 """Represents the HTTP/2 Interop Test
183
184 This pretends to be a language in order to be built and run, but really it
185 isn't.
186 """
187 def __init__(self):
188 self.client_cwd = None
189 self.safename = str(self)
190
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800191 def client_cmd(self, args):
192 return ['tools/http2_interop/http2_interop.test', '-test.v'] + args
Carl Mastrangelode449102015-10-28 11:05:49 -0700193
194 def cloud_to_prod_env(self):
195 return {}
196
197 def global_env(self):
198 return {}
199
200 def unimplemented_test_cases(self):
201 return _TEST_CASES
202
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800203 def unimplemented_test_cases_server(self):
204 return []
205
Carl Mastrangelode449102015-10-28 11:05:49 -0700206 def __str__(self):
207 return 'http2'
208
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700209class NodeLanguage:
210
211 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700212 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700213 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700214 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700215
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700216 def client_cmd(self, args):
217 return ['node', 'src/node/interop/interop_client.js'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700218
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700219 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800220 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700221
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700222 def server_cmd(self, args):
223 return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700224
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700225 def global_env(self):
226 return {}
227
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700228 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800229 return _SKIP_COMPRESSION
230
231 def unimplemented_test_cases_server(self):
232 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700233
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700234 def __str__(self):
235 return 'node'
236
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700237
238class PHPLanguage:
239
240 def __init__(self):
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700241 self.client_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700242 self.safename = str(self)
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700243
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700244 def client_cmd(self, args):
245 return ['src/php/bin/interop_client.sh'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700246
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700247 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800248 return {}
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700249
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700250 def global_env(self):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700251 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700252
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700253 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800254 return _SKIP_ADVANCED + _SKIP_COMPRESSION
255
256 def unimplemented_test_cases_server(self):
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700257 return []
258
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700259 def __str__(self):
260 return 'php'
261
262
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700263class RubyLanguage:
264
265 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700266 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700267 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700268 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700269
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700270 def client_cmd(self, args):
271 return ['ruby', 'src/ruby/bin/interop/interop_client.rb'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700272
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700273 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800274 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700275
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700276 def server_cmd(self, args):
277 return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700278
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700279 def global_env(self):
280 return {}
281
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700282 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800283 return _SKIP_ADVANCED + _SKIP_COMPRESSION
284
285 def unimplemented_test_cases_server(self):
286 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700287
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700288 def __str__(self):
289 return 'ruby'
290
291
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700292class PythonLanguage:
293
294 def __init__(self):
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700295 self.client_cwd = None
296 self.server_cwd = None
297 self.safename = str(self)
298
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700299 def client_cmd(self, args):
300 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800301 'tox -einterop_client --',
302 ' '.join(args)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700303 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700304
305 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800306 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700307
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700308 def server_cmd(self, args):
309 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800310 'tox -einterop_server --',
311 ' '.join(args) + ' --use_tls=true'
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700312 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700313
314 def global_env(self):
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700315 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700316
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700317 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800318 return _SKIP_ADVANCED + _SKIP_COMPRESSION + ['jwt_token_creds',
319 'per_rpc_creds']
320
321 def unimplemented_test_cases_server(self):
322 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700323
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700324 def __str__(self):
325 return 'python'
326
327
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700328_LANGUAGES = {
329 'c++' : CXXLanguage(),
330 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700331 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700332 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700333 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700334 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700335 'ruby' : RubyLanguage(),
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700336 'python' : PythonLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700337}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700338
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700339# languages supported as cloud_to_cloud servers
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700340_SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby', 'python']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700341
Jan Tattermusch320bd612015-09-15 12:44:35 -0700342_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch1f1c5c52015-10-09 14:36:28 -0700343 'empty_stream', 'client_streaming', 'server_streaming',
Jan Tattermusch13bf36a2015-10-14 17:01:00 -0700344 'cancel_after_begin', 'cancel_after_first_response',
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800345 'timeout_on_sleeping_server', 'custom_metadata',
346 'status_code_and_message', 'unimplemented_method',
347 'large_compressed_unary', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700348
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700349_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
350 'oauth2_auth_token', 'per_rpc_creds']
351
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800352_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700353
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700354DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
355
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700356def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
357 """Wraps given cmdline array to create 'docker run' cmdline from it."""
358 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
359
360 # turn environ into -e docker args
361 if environ:
362 for k,v in environ.iteritems():
363 docker_cmdline += ['-e', '%s=%s' % (k,v)]
364
365 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700366 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700367 if cwd:
368 workdir = os.path.join(workdir, cwd)
369 docker_cmdline += ['-w', workdir]
370
371 docker_cmdline += docker_args + [image] + cmdline
372 return docker_cmdline
373
374
375def bash_login_cmdline(cmdline):
376 """Creates bash -l -c cmdline from args list."""
377 # Use login shell:
378 # * rvm and nvm require it
379 # * makes error messages clearer if executables are missing
380 return ['bash', '-l', '-c', ' '.join(cmdline)]
381
382
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800383def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700384 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
385
386 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800387 cmdargs = []
388 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700389
390 # TODO(jtattermusch): this file path only works inside docker
391 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
392 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
393 key_file_arg = '--service_account_key_file=%s' % key_filepath
394 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
395
396 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700397 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700398 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
399 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800400 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700401
402 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800403 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700404
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700405 if test_case == 'oauth2_auth_token' and language == 'c++':
406 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800407 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700408
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700409 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800410 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700411
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800412 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700413
414
Jan Tattermusche2686282015-10-08 16:27:07 -0700415def _job_kill_handler(job):
416 if job._spec.container_name:
417 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700418 # When the job times out and we decide to kill it,
419 # we need to wait a before restarting the job
420 # to prevent "container name already in use" error.
421 # TODO(jtattermusch): figure out a cleaner way to to this.
422 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700423
424
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800425def cloud_to_prod_jobspec(language, test_case, server_host_name,
426 server_host_detail, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700427 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800428 container_name = None
429 cmdargs = [
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800430 '--server_host=%s' % server_host_detail[0],
431 '--server_host_override=%s' % server_host_detail[1],
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700432 '--server_port=443',
433 '--use_tls=true',
434 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700435 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700436 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800437 auth_cmdargs, auth_env = auth_options(language, test_case)
438 cmdargs += auth_cmdargs
439 environ.update(auth_env)
440 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
441 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700442
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700443 if docker_image:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800444 container_name = dockerjob.random_name('interop_client_%s' %
445 language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700446 cmdline = docker_run_cmdline(cmdline,
447 image=docker_image,
448 cwd=cwd,
449 environ=environ,
450 docker_args=['--net=host',
451 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700452 cwd = None
453 environ = None
454
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700455 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700456 test_job = jobset.JobSpec(
457 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700458 cwd=cwd,
459 environ=environ,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800460 shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
461 test_case),
Jan Tattermusch29fd0052015-10-22 18:58:57 -0700462 timeout_seconds=90,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700463 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700464 timeout_retries=2 if args.allow_flakes else 0,
465 kill_handler=_job_kill_handler)
466 test_job.container_name = container_name
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700467 return test_job
468
Jan Tattermusch8266c672015-09-17 09:18:03 -0700469
470def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700471 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700472 """Creates jobspec for cloud-to-cloud interop test"""
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700473 cmdline = bash_login_cmdline(language.client_cmd([
474 '--server_host_override=foo.test.google.fr',
475 '--use_tls=true',
476 '--use_test_ca=true',
477 '--test_case=%s' % test_case,
478 '--server_host=%s' % server_host,
479 '--server_port=%s' % server_port]))
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700480 cwd = language.client_cwd
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700481 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700482 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700483 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700484 cmdline = docker_run_cmdline(cmdline,
485 image=docker_image,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700486 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700487 cwd=cwd,
Jan Tattermusche2686282015-10-08 16:27:07 -0700488 docker_args=['--net=host',
489 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700490 cwd = None
Jan Tattermusche2686282015-10-08 16:27:07 -0700491
Jan Tattermusch8266c672015-09-17 09:18:03 -0700492 test_job = jobset.JobSpec(
493 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700494 cwd=cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700495 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700496 shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800497 test_case),
Jan Tattermusch29fd0052015-10-22 18:58:57 -0700498 timeout_seconds=90,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700499 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700500 timeout_retries=2 if args.allow_flakes else 0,
501 kill_handler=_job_kill_handler)
502 test_job.container_name = container_name
Jan Tattermusch8266c672015-09-17 09:18:03 -0700503 return test_job
504
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700505
506def server_jobspec(language, docker_image):
507 """Create jobspec for running a server"""
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700508 container_name = dockerjob.random_name('interop_server_%s' % language.safename)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700509 cmdline = bash_login_cmdline(
510 language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700511 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700512 docker_cmdline = docker_run_cmdline(cmdline,
513 image=docker_image,
514 cwd=language.server_cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700515 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700516 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
Jan Tattermusche2686282015-10-08 16:27:07 -0700517 '--name', container_name])
Carl Mastrangelode449102015-10-28 11:05:49 -0700518
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700519 server_job = jobset.JobSpec(
520 cmdline=docker_cmdline,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700521 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700522 shortname='interop_server_%s' % language,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700523 timeout_seconds=30*60)
Jan Tattermusche2686282015-10-08 16:27:07 -0700524 server_job.container_name = container_name
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700525 return server_job
526
527
528def build_interop_image_jobspec(language, tag=None):
529 """Creates jobspec for building interop docker image for a language"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700530 if not tag:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700531 tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700532 env = {'INTEROP_IMAGE': tag,
533 'BASE_NAME': 'grpc_interop_%s' % language.safename}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700534 if not args.travis:
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700535 env['TTY_FLAG'] = '-t'
536 # This env variable is used to get around the github rate limit
537 # error when running the PHP `composer install` command
538 # TODO(stanleycheung): find a more elegant way to do this
Stanley Cheungf565dfb2015-10-15 17:57:09 -0700539 if language.safename == 'php' and os.path.exists('/var/local/.composer/auth.json'):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700540 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Adele Zhoue4c35612015-10-16 15:34:23 -0700541 '-v /var/local/.composer/auth.json:/root/.composer/auth.json:ro'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700542 build_job = jobset.JobSpec(
543 cmdline=['tools/jenkins/build_interop_image.sh'],
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700544 environ=env,
Adele Zhoue4c35612015-10-16 15:34:23 -0700545 shortname='build_docker_%s' % (language),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700546 timeout_seconds=30*60)
547 build_job.tag = tag
548 return build_job
549
550
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800551def aggregate_http2_results(stdout):
552 match = re.search(r'\{"cases[^\]]*\]\}', stdout)
553 if not match:
554 return None
murgatroid99c3910ca2016-01-06 13:14:23 -0800555
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800556 results = json.loads(match.group(0))
557 skipped = 0
558 passed = 0
559 failed = 0
560 failed_cases = []
561 for case in results['cases']:
562 if case.get('skipped', False):
563 skipped += 1
564 else:
565 if case.get('passed', False):
566 passed += 1
567 else:
568 failed += 1
569 failed_cases.append(case.get('name', "NONAME"))
570 return {
571 'passed': passed,
572 'failed': failed,
573 'skipped': skipped,
574 'failed_cases': ', '.join(failed_cases),
575 'percent': 1.0 * passed / (passed + failed)
576 }
577
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800578# A dictionary of prod servers to test.
579# Format: server_name: (server_host, server_host_override, errors_allowed)
580# TODO(adelez): implement logic for errors_allowed where if the indicated tests
581# fail, they don't impact the overall test result.
582prod_servers = {
583 'default': ('grpc-test.sandbox.googleapis.com',
584 'grpc-test.sandbox.googleapis.com', False),
585 'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
586 'grpc-test2.sandbox.googleapis.com', True),
587 'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
588 False),
589 'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
590 True)
591}
592
Jan Tattermusch320bd612015-09-15 12:44:35 -0700593argp = argparse.ArgumentParser(description='Run interop tests.')
594argp.add_argument('-l', '--language',
595 choices=['all'] + sorted(_LANGUAGES),
596 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700597 default=['all'],
598 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700599argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700600argp.add_argument('--cloud_to_prod',
601 default=False,
602 action='store_const',
603 const=True,
604 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700605argp.add_argument('--cloud_to_prod_auth',
606 default=False,
607 action='store_const',
608 const=True,
609 help='Run cloud_to_prod_auth tests.')
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800610argp.add_argument('--prod_servers',
611 choices=prod_servers.keys(),
612 default=['default'],
613 nargs='+',
614 help=('The servers to run cloud_to_prod and '
615 'cloud_to_prod_auth tests against.'))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700616argp.add_argument('-s', '--server',
617 choices=['all'] + sorted(_SERVERS),
618 action='append',
619 help='Run cloud_to_cloud servers in a separate docker ' +
620 'image. Servers can only be started automatically if ' +
621 '--use_docker option is enabled.',
622 default=[])
623argp.add_argument('--override_server',
624 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700625 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700626 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
627 default=[])
628argp.add_argument('-t', '--travis',
629 default=False,
630 action='store_const',
631 const=True)
632argp.add_argument('--use_docker',
633 default=False,
634 action='store_const',
635 const=True,
636 help='Run all the interop tests under docker. That provides ' +
637 'additional isolation and prevents the need to install ' +
638 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700639argp.add_argument('--allow_flakes',
640 default=False,
641 action='store_const',
642 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700643 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700644argp.add_argument('--http2_interop',
645 default=False,
646 action='store_const',
647 const=True,
648 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800649
Jan Tattermusch320bd612015-09-15 12:44:35 -0700650args = argp.parse_args()
651
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700652servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700653 if x == 'all' else [x]
654 for x in args.server))
655
656if args.use_docker:
657 if not args.travis:
658 print 'Seen --use_docker flag, will run interop tests under docker.'
659 print
660 print 'IMPORTANT: The changes you are testing need to be locally committed'
661 print 'because only the committed changes in the current branch will be'
662 print 'copied to the docker environment.'
663 time.sleep(5)
664
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700665if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700666 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700667 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700668
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700669languages = set(_LANGUAGES[l]
670 for l in itertools.chain.from_iterable(
671 _LANGUAGES.iterkeys() if x == 'all' else [x]
672 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800673
Carl Mastrangelode449102015-10-28 11:05:49 -0700674http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700675
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700676docker_images={}
677if args.use_docker:
678 # languages for which to build docker images
679 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
680 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700681 if args.http2_interop:
682 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700683
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700684 build_jobs = []
685 for l in languages_to_build:
686 job = build_interop_image_jobspec(l)
687 docker_images[str(l)] = job.tag
688 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700689
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700690 if build_jobs:
691 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700692 num_failures, _ = jobset.run(
693 build_jobs, newline_on_success=True, maxjobs=args.jobs)
694 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800695 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700696 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700697 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800698 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700699 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700700 for image in docker_images.itervalues():
701 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700702 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700703
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700704# Start interop servers.
705server_jobs={}
706server_addresses={}
707try:
708 for s in servers:
709 lang = str(s)
710 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
711 job = dockerjob.DockerJob(spec)
712 server_jobs[lang] = job
713 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700714
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700715 jobs = []
716 if args.cloud_to_prod:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800717 for server_host_name in args.prod_servers:
718 for language in languages:
719 for test_case in _TEST_CASES:
720 if not test_case in language.unimplemented_test_cases():
721 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
722 test_job = cloud_to_prod_jobspec(
723 language, test_case, server_host_name,
724 prod_servers[server_host_name],
725 docker_image=docker_images.get(str(language)))
726 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800727
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800728 if args.http2_interop:
729 for test_case in _HTTP2_TEST_CASES:
730 test_job = cloud_to_prod_jobspec(
731 http2Interop, test_case, server_host_name,
732 prod_servers[server_host_name],
733 docker_image=docker_images.get(str(http2Interop)))
734 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700735
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700736 if args.cloud_to_prod_auth:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800737 for server_host_name in args.prod_servers:
738 for language in languages:
739 for test_case in _AUTH_TEST_CASES:
740 if not test_case in language.unimplemented_test_cases():
741 test_job = cloud_to_prod_jobspec(
742 language, test_case, server_host_name,
743 prod_servers[server_host_name],
744 docker_image=docker_images.get(str(language)), auth=True)
745 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700746
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700747 for server in args.override_server:
748 server_name = server[0]
749 (server_host, server_port) = server[1].split(':')
750 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700751
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700752 for server_name, server_address in server_addresses.iteritems():
753 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800754 server_language = _LANGUAGES.get(server_name, None)
755 skip_server = [] # test cases unimplemented by server
756 if server_language:
757 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700758 for language in languages:
759 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700760 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800761 if not test_case in skip_server:
762 test_job = cloud_to_cloud_jobspec(language,
763 test_case,
764 server_name,
765 server_host,
766 server_port,
767 docker_image=docker_images.get(str(language)))
768 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800769
Carl Mastrangelode449102015-10-28 11:05:49 -0700770 if args.http2_interop:
771 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800772 if server_name == "go":
773 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
murgatroid99c3910ca2016-01-06 13:14:23 -0800774 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700775 test_job = cloud_to_cloud_jobspec(http2Interop,
776 test_case,
777 server_name,
778 server_host,
779 server_port,
780 docker_image=docker_images.get(str(http2Interop)))
781 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700782
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700783 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700784 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700785 for image in docker_images.itervalues():
786 dockerjob.remove_image(image, skip_nonexistent=True)
787 sys.exit(1)
788
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800789 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700790 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700791 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700792 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700793 else:
794 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700795
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800796 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800797
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800798 for name, job in resultset.iteritems():
799 if "http2" in name:
800 job[0].http2results = aggregate_http2_results(job[0].message)
801
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800802 report_utils.render_interop_html_report(
murgatroid99c3910ca2016-01-06 13:14:23 -0800803 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700804 _HTTP2_TEST_CASES, resultset, num_failures,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800805 args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers,
806 args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700807
808finally:
809 # Check if servers are still running.
810 for server, job in server_jobs.iteritems():
811 if not job.is_running():
812 print 'Server "%s" has exited prematurely.' % server
813
814 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
815
816 for image in docker_images.itervalues():
817 print 'Removing docker image %s' % image
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800818 dockerjob.remove_image(image)