blob: e69e9877c5c7f272fd1f4e9fd689cfe92b32506f [file] [log] [blame]
Jan Tattermusch320bd612015-09-15 12:44:35 -07001#!/usr/bin/env python
2# Copyright 2015, Google Inc.
3# 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 Malekghassemieaa7d202015-12-07 14:38:53 -0800301 'src/python/grpcio/.tox/py27/bin/python',
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700302 'src/python/grpcio/setup.py',
303 'run_interop',
304 '--client',
305 '--args=\'{}\''.format(' '.join(args))
306 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700307
308 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800309 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700310
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700311 def server_cmd(self, args):
312 return [
Masood Malekghassemieaa7d202015-12-07 14:38:53 -0800313 'src/python/grpcio/.tox/py27/bin/python',
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700314 'src/python/grpcio/setup.py',
315 'run_interop',
316 '--server',
317 '--args=\'{}\''.format(' '.join(args) + ' --use_tls=true')
318 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700319
320 def global_env(self):
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700321 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700322
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700323 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800324 return _SKIP_ADVANCED + _SKIP_COMPRESSION + ['jwt_token_creds',
325 'per_rpc_creds']
326
327 def unimplemented_test_cases_server(self):
328 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700329
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700330 def __str__(self):
331 return 'python'
332
333
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700334_LANGUAGES = {
335 'c++' : CXXLanguage(),
336 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700337 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700338 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700339 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700340 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700341 'ruby' : RubyLanguage(),
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700342 'python' : PythonLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700343}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700344
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700345# languages supported as cloud_to_cloud servers
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700346_SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby', 'python']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700347
Jan Tattermusch320bd612015-09-15 12:44:35 -0700348_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch1f1c5c52015-10-09 14:36:28 -0700349 'empty_stream', 'client_streaming', 'server_streaming',
Jan Tattermusch13bf36a2015-10-14 17:01:00 -0700350 'cancel_after_begin', 'cancel_after_first_response',
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800351 'timeout_on_sleeping_server', 'custom_metadata',
352 'status_code_and_message', 'unimplemented_method',
353 'large_compressed_unary', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700354
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700355_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
356 'oauth2_auth_token', 'per_rpc_creds']
357
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800358_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700359
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700360DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
361
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700362def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
363 """Wraps given cmdline array to create 'docker run' cmdline from it."""
364 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
365
366 # turn environ into -e docker args
367 if environ:
368 for k,v in environ.iteritems():
369 docker_cmdline += ['-e', '%s=%s' % (k,v)]
370
371 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700372 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700373 if cwd:
374 workdir = os.path.join(workdir, cwd)
375 docker_cmdline += ['-w', workdir]
376
377 docker_cmdline += docker_args + [image] + cmdline
378 return docker_cmdline
379
380
381def bash_login_cmdline(cmdline):
382 """Creates bash -l -c cmdline from args list."""
383 # Use login shell:
384 # * rvm and nvm require it
385 # * makes error messages clearer if executables are missing
386 return ['bash', '-l', '-c', ' '.join(cmdline)]
387
388
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800389def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700390 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
391
392 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800393 cmdargs = []
394 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700395
396 # TODO(jtattermusch): this file path only works inside docker
397 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
398 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
399 key_file_arg = '--service_account_key_file=%s' % key_filepath
400 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
401
402 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700403 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700404 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
405 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800406 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700407
408 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800409 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700410
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700411 if test_case == 'oauth2_auth_token' and language == 'c++':
412 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800413 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700414
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700415 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800416 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700417
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800418 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700419
420
Jan Tattermusche2686282015-10-08 16:27:07 -0700421def _job_kill_handler(job):
422 if job._spec.container_name:
423 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700424 # When the job times out and we decide to kill it,
425 # we need to wait a before restarting the job
426 # to prevent "container name already in use" error.
427 # TODO(jtattermusch): figure out a cleaner way to to this.
428 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700429
430
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700431def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700432 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800433 container_name = None
434 cmdargs = [
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700435 '--server_host_override=grpc-test.sandbox.google.com',
436 '--server_host=grpc-test.sandbox.google.com',
437 '--server_port=443',
438 '--use_tls=true',
439 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700440 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700441 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800442 auth_cmdargs, auth_env = auth_options(language, test_case)
443 cmdargs += auth_cmdargs
444 environ.update(auth_env)
445 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
446 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700447
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700448 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700449 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700450 cmdline = docker_run_cmdline(cmdline,
451 image=docker_image,
452 cwd=cwd,
453 environ=environ,
454 docker_args=['--net=host',
455 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700456 cwd = None
457 environ = None
458
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700459 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700460 test_job = jobset.JobSpec(
461 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700462 cwd=cwd,
463 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700464 shortname='%s:%s:%s' % (suite_name, language, test_case),
Jan Tattermusch29fd0052015-10-22 18:58:57 -0700465 timeout_seconds=90,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700466 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700467 timeout_retries=2 if args.allow_flakes else 0,
468 kill_handler=_job_kill_handler)
469 test_job.container_name = container_name
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700470 return test_job
471
Jan Tattermusch8266c672015-09-17 09:18:03 -0700472
473def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700474 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700475 """Creates jobspec for cloud-to-cloud interop test"""
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700476 cmdline = bash_login_cmdline(language.client_cmd([
477 '--server_host_override=foo.test.google.fr',
478 '--use_tls=true',
479 '--use_test_ca=true',
480 '--test_case=%s' % test_case,
481 '--server_host=%s' % server_host,
482 '--server_port=%s' % server_port]))
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700483 cwd = language.client_cwd
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700484 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700485 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700486 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700487 cmdline = docker_run_cmdline(cmdline,
488 image=docker_image,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700489 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700490 cwd=cwd,
Jan Tattermusche2686282015-10-08 16:27:07 -0700491 docker_args=['--net=host',
492 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700493 cwd = None
Jan Tattermusche2686282015-10-08 16:27:07 -0700494
Jan Tattermusch8266c672015-09-17 09:18:03 -0700495 test_job = jobset.JobSpec(
496 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700497 cwd=cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700498 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700499 shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
Jan Tattermusch8266c672015-09-17 09:18:03 -0700500 test_case),
Jan Tattermusch29fd0052015-10-22 18:58:57 -0700501 timeout_seconds=90,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700502 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700503 timeout_retries=2 if args.allow_flakes else 0,
504 kill_handler=_job_kill_handler)
505 test_job.container_name = container_name
Jan Tattermusch8266c672015-09-17 09:18:03 -0700506 return test_job
507
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700508
509def server_jobspec(language, docker_image):
510 """Create jobspec for running a server"""
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700511 container_name = dockerjob.random_name('interop_server_%s' % language.safename)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700512 cmdline = bash_login_cmdline(
513 language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700514 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700515 docker_cmdline = docker_run_cmdline(cmdline,
516 image=docker_image,
517 cwd=language.server_cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700518 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700519 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
Jan Tattermusche2686282015-10-08 16:27:07 -0700520 '--name', container_name])
Carl Mastrangelode449102015-10-28 11:05:49 -0700521
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700522 server_job = jobset.JobSpec(
523 cmdline=docker_cmdline,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700524 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700525 shortname='interop_server_%s' % language,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700526 timeout_seconds=30*60)
Jan Tattermusche2686282015-10-08 16:27:07 -0700527 server_job.container_name = container_name
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700528 return server_job
529
530
531def build_interop_image_jobspec(language, tag=None):
532 """Creates jobspec for building interop docker image for a language"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700533 if not tag:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700534 tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700535 env = {'INTEROP_IMAGE': tag,
536 'BASE_NAME': 'grpc_interop_%s' % language.safename}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700537 if not args.travis:
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700538 env['TTY_FLAG'] = '-t'
539 # This env variable is used to get around the github rate limit
540 # error when running the PHP `composer install` command
541 # TODO(stanleycheung): find a more elegant way to do this
Stanley Cheungf565dfb2015-10-15 17:57:09 -0700542 if language.safename == 'php' and os.path.exists('/var/local/.composer/auth.json'):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700543 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Adele Zhoue4c35612015-10-16 15:34:23 -0700544 '-v /var/local/.composer/auth.json:/root/.composer/auth.json:ro'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700545 build_job = jobset.JobSpec(
546 cmdline=['tools/jenkins/build_interop_image.sh'],
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700547 environ=env,
Adele Zhoue4c35612015-10-16 15:34:23 -0700548 shortname='build_docker_%s' % (language),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700549 timeout_seconds=30*60)
550 build_job.tag = tag
551 return build_job
552
553
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800554def aggregate_http2_results(stdout):
555 match = re.search(r'\{"cases[^\]]*\]\}', stdout)
556 if not match:
557 return None
558
559 results = json.loads(match.group(0))
560 skipped = 0
561 passed = 0
562 failed = 0
563 failed_cases = []
564 for case in results['cases']:
565 if case.get('skipped', False):
566 skipped += 1
567 else:
568 if case.get('passed', False):
569 passed += 1
570 else:
571 failed += 1
572 failed_cases.append(case.get('name', "NONAME"))
573 return {
574 'passed': passed,
575 'failed': failed,
576 'skipped': skipped,
577 'failed_cases': ', '.join(failed_cases),
578 'percent': 1.0 * passed / (passed + failed)
579 }
580
Jan Tattermusch320bd612015-09-15 12:44:35 -0700581argp = argparse.ArgumentParser(description='Run interop tests.')
582argp.add_argument('-l', '--language',
583 choices=['all'] + sorted(_LANGUAGES),
584 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700585 default=['all'],
586 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700587argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700588argp.add_argument('--cloud_to_prod',
589 default=False,
590 action='store_const',
591 const=True,
592 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700593argp.add_argument('--cloud_to_prod_auth',
594 default=False,
595 action='store_const',
596 const=True,
597 help='Run cloud_to_prod_auth tests.')
Jan Tattermusch8266c672015-09-17 09:18:03 -0700598argp.add_argument('-s', '--server',
599 choices=['all'] + sorted(_SERVERS),
600 action='append',
601 help='Run cloud_to_cloud servers in a separate docker ' +
602 'image. Servers can only be started automatically if ' +
603 '--use_docker option is enabled.',
604 default=[])
605argp.add_argument('--override_server',
606 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700607 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700608 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
609 default=[])
610argp.add_argument('-t', '--travis',
611 default=False,
612 action='store_const',
613 const=True)
614argp.add_argument('--use_docker',
615 default=False,
616 action='store_const',
617 const=True,
618 help='Run all the interop tests under docker. That provides ' +
619 'additional isolation and prevents the need to install ' +
620 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700621argp.add_argument('--allow_flakes',
622 default=False,
623 action='store_const',
624 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700625 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700626argp.add_argument('--http2_interop',
627 default=False,
628 action='store_const',
629 const=True,
630 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800631
Jan Tattermusch320bd612015-09-15 12:44:35 -0700632args = argp.parse_args()
633
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700634servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700635 if x == 'all' else [x]
636 for x in args.server))
637
638if args.use_docker:
639 if not args.travis:
640 print 'Seen --use_docker flag, will run interop tests under docker.'
641 print
642 print 'IMPORTANT: The changes you are testing need to be locally committed'
643 print 'because only the committed changes in the current branch will be'
644 print 'copied to the docker environment.'
645 time.sleep(5)
646
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700647if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700648 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700649 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700650
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700651languages = set(_LANGUAGES[l]
652 for l in itertools.chain.from_iterable(
653 _LANGUAGES.iterkeys() if x == 'all' else [x]
654 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800655
Carl Mastrangelode449102015-10-28 11:05:49 -0700656http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700657
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700658docker_images={}
659if args.use_docker:
660 # languages for which to build docker images
661 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
662 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700663 if args.http2_interop:
664 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700665
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700666 build_jobs = []
667 for l in languages_to_build:
668 job = build_interop_image_jobspec(l)
669 docker_images[str(l)] = job.tag
670 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700671
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700672 if build_jobs:
673 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700674 num_failures, _ = jobset.run(
675 build_jobs, newline_on_success=True, maxjobs=args.jobs)
676 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800677 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700678 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700679 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800680 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700681 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700682 for image in docker_images.itervalues():
683 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700684 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700685
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700686# Start interop servers.
687server_jobs={}
688server_addresses={}
689try:
690 for s in servers:
691 lang = str(s)
692 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
693 job = dockerjob.DockerJob(spec)
694 server_jobs[lang] = job
695 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700696
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700697
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700698 jobs = []
699 if args.cloud_to_prod:
700 for language in languages:
701 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700702 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800703 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
704 test_job = cloud_to_prod_jobspec(language, test_case,
705 docker_image=docker_images.get(str(language)))
706 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800707
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800708 if args.http2_interop:
Carl Mastrangelode449102015-10-28 11:05:49 -0700709 for test_case in _HTTP2_TEST_CASES:
710 test_job = cloud_to_prod_jobspec(http2Interop, test_case,
711 docker_image=docker_images.get(str(http2Interop)))
712 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800713
Jan Tattermusch320bd612015-09-15 12:44:35 -0700714
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700715 if args.cloud_to_prod_auth:
716 for language in languages:
717 for test_case in _AUTH_TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700718 if not test_case in language.unimplemented_test_cases():
719 test_job = cloud_to_prod_jobspec(language, test_case,
720 docker_image=docker_images.get(str(language)),
721 auth=True)
722 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700723
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700724 for server in args.override_server:
725 server_name = server[0]
726 (server_host, server_port) = server[1].split(':')
727 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700728
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700729 for server_name, server_address in server_addresses.iteritems():
730 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800731 server_language = _LANGUAGES.get(server_name, None)
732 skip_server = [] # test cases unimplemented by server
733 if server_language:
734 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700735 for language in languages:
736 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700737 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800738 if not test_case in skip_server:
739 test_job = cloud_to_cloud_jobspec(language,
740 test_case,
741 server_name,
742 server_host,
743 server_port,
744 docker_image=docker_images.get(str(language)))
745 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800746
Carl Mastrangelode449102015-10-28 11:05:49 -0700747 if args.http2_interop:
748 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800749 if server_name == "go":
750 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
Jorge Canizales340661d2015-12-07 13:34:57 -0800751 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700752 test_job = cloud_to_cloud_jobspec(http2Interop,
753 test_case,
754 server_name,
755 server_host,
756 server_port,
757 docker_image=docker_images.get(str(http2Interop)))
758 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700759
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700760 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700761 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700762 for image in docker_images.itervalues():
763 dockerjob.remove_image(image, skip_nonexistent=True)
764 sys.exit(1)
765
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800766 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700767 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700768 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700769 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700770 else:
771 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700772
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800773 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800774
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800775 for name, job in resultset.iteritems():
776 if "http2" in name:
777 job[0].http2results = aggregate_http2_results(job[0].message)
778
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800779 report_utils.render_interop_html_report(
Adele Zhou2271ab52015-10-28 13:59:14 -0700780 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700781 _HTTP2_TEST_CASES, resultset, num_failures,
782 args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700783
784finally:
785 # Check if servers are still running.
786 for server, job in server_jobs.iteritems():
787 if not job.is_running():
788 print 'Server "%s" has exited prematurely.' % server
789
790 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
791
792 for image in docker_images.itervalues():
793 print 'Removing docker image %s' % image
794 dockerjob.remove_image(image)