blob: 0787637d75851976d6e7fbe4a6cbe38c6a4b9e66 [file] [log] [blame]
Nathaniel Manistacbf21da2016-02-02 22:17:44 +00001#!/usr/bin/env python2.7
Craig Tiller6169d5f2016-03-31 07:46:18 -07002# Copyright 2015, 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 Tattermusch19f703d2016-03-03 15:33:29 -080063_TEST_TIMEOUT = 3*60
64
Jan Tattermuschf49936a2015-09-16 15:44:26 -070065class CXXLanguage:
66
67 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -070068 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -070069 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -070070 self.safename = 'cxx'
Jan Tattermuschf49936a2015-09-16 15:44:26 -070071
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070072 def client_cmd(self, args):
73 return ['bins/opt/interop_client'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -070074
Jan Tattermuschf49936a2015-09-16 15:44:26 -070075 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -070076 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -070077
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070078 def server_cmd(self, args):
79 return ['bins/opt/interop_server', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -070080
Masood Malekghassemi18cc8422015-10-09 17:55:45 -070081 def global_env(self):
82 return {}
83
Jan Tattermusch289b7b92015-10-21 18:09:59 -070084 def unimplemented_test_cases(self):
David Garcia Quintas303d3082016-05-05 18:25:34 -070085 return _SKIP_ADVANCED
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080086
87 def unimplemented_test_cases_server(self):
David Garcia Quintas303d3082016-05-05 18:25:34 -070088 return _SKIP_ADVANCED
Jan Tattermusch289b7b92015-10-21 18:09:59 -070089
Jan Tattermuschf49936a2015-09-16 15:44:26 -070090 def __str__(self):
91 return 'c++'
92
93
94class CSharpLanguage:
95
96 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -070097 self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug'
Jan Tattermusch91ad0182015-10-01 09:22:03 -070098 self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
Jan Tattermusch0a14f622015-10-09 14:34:29 -070099 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700100
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700101 def client_cmd(self, args):
102 return ['mono', 'Grpc.IntegrationTesting.Client.exe'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700103
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700104 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800105 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700106
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700107 def server_cmd(self, args):
108 return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700109
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700110 def global_env(self):
111 return {}
112
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700113 def unimplemented_test_cases(self):
Jan Tattermusch85a93832016-04-27 11:11:41 -0700114 return _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800115
116 def unimplemented_test_cases_server(self):
117 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700118
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700119 def __str__(self):
120 return 'csharp'
121
122
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700123class JavaLanguage:
124
125 def __init__(self):
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700126 self.client_cwd = '../grpc-java'
127 self.server_cwd = '../grpc-java'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700128 self.safename = str(self)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700129
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700130 def client_cmd(self, args):
131 return ['./run-test-client.sh'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700132
133 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700134 return {}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700135
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700136 def server_cmd(self, args):
137 return ['./run-test-server.sh', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700138
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700139 def global_env(self):
140 return {}
141
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700142 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800143 return _SKIP_ADVANCED + _SKIP_COMPRESSION
144
145 def unimplemented_test_cases_server(self):
146 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700147
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700148 def __str__(self):
149 return 'java'
150
151
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700152class GoLanguage:
153
154 def __init__(self):
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700155 # TODO: this relies on running inside docker
156 self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
157 self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700158 self.safename = str(self)
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700159
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700160 def client_cmd(self, args):
161 return ['go', 'run', 'client.go'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700162
163 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700164 return {}
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700165
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700166 def server_cmd(self, args):
167 return ['go', 'run', 'server.go', '--use_tls=true'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700168
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700169 def global_env(self):
170 return {}
171
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700172 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800173 return _SKIP_ADVANCED + _SKIP_COMPRESSION
174
175 def unimplemented_test_cases_server(self):
176 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700177
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700178 def __str__(self):
179 return 'go'
180
181
Carl Mastrangelode449102015-10-28 11:05:49 -0700182class Http2Client:
183 """Represents the HTTP/2 Interop Test
184
185 This pretends to be a language in order to be built and run, but really it
186 isn't.
187 """
188 def __init__(self):
189 self.client_cwd = None
190 self.safename = str(self)
191
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800192 def client_cmd(self, args):
193 return ['tools/http2_interop/http2_interop.test', '-test.v'] + args
Carl Mastrangelode449102015-10-28 11:05:49 -0700194
195 def cloud_to_prod_env(self):
196 return {}
197
198 def global_env(self):
199 return {}
200
201 def unimplemented_test_cases(self):
202 return _TEST_CASES
203
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800204 def unimplemented_test_cases_server(self):
205 return []
206
Carl Mastrangelode449102015-10-28 11:05:49 -0700207 def __str__(self):
208 return 'http2'
209
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700210class NodeLanguage:
211
212 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700213 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700214 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700215 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700216
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700217 def client_cmd(self, args):
218 return ['node', 'src/node/interop/interop_client.js'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700219
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700220 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800221 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700222
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700223 def server_cmd(self, args):
224 return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700225
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700226 def global_env(self):
227 return {}
228
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700229 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800230 return _SKIP_COMPRESSION
231
232 def unimplemented_test_cases_server(self):
233 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700234
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700235 def __str__(self):
236 return 'node'
237
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700238
239class PHPLanguage:
240
241 def __init__(self):
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700242 self.client_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700243 self.safename = str(self)
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700244
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700245 def client_cmd(self, args):
246 return ['src/php/bin/interop_client.sh'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700247
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700248 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800249 return {}
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700250
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700251 def global_env(self):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700252 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700253
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700254 def unimplemented_test_cases(self):
Stanley Cheung83d8e372016-06-17 11:53:33 -0700255 return _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800256
257 def unimplemented_test_cases_server(self):
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700258 return []
259
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700260 def __str__(self):
261 return 'php'
262
263
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700264class RubyLanguage:
265
266 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700267 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700268 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700269 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700270
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700271 def client_cmd(self, args):
murgatroid99e621f132016-04-21 14:28:00 -0700272 return ['ruby', 'src/ruby/pb/test/client.rb'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700273
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700274 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800275 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700276
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700277 def server_cmd(self, args):
murgatroid99e621f132016-04-21 14:28:00 -0700278 return ['ruby', 'src/ruby/pb/test/server.rb', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700279
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700280 def global_env(self):
281 return {}
282
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700283 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800284 return _SKIP_ADVANCED + _SKIP_COMPRESSION
285
286 def unimplemented_test_cases_server(self):
287 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700288
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700289 def __str__(self):
290 return 'ruby'
291
292
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700293class PythonLanguage:
294
295 def __init__(self):
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700296 self.client_cwd = None
297 self.server_cwd = None
298 self.safename = str(self)
299
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700300 def client_cmd(self, args):
301 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800302 'tox -einterop_client --',
303 ' '.join(args)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700304 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700305
306 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800307 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700308
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700309 def server_cmd(self, args):
310 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800311 'tox -einterop_server --',
312 ' '.join(args) + ' --use_tls=true'
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700313 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700314
315 def global_env(self):
Ken Payson707c9e22016-04-20 09:42:19 -0700316 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT),
317 'PYTHONPATH': '{}/src/python/gens'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700318
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700319 def unimplemented_test_cases(self):
Ken Payson22a65e12016-06-07 19:06:05 -0700320 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800321
322 def unimplemented_test_cases_server(self):
323 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700324
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700325 def __str__(self):
326 return 'python'
327
328
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700329_LANGUAGES = {
330 'c++' : CXXLanguage(),
331 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700332 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700333 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700334 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700335 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700336 'ruby' : RubyLanguage(),
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700337 'python' : PythonLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700338}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700339
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700340# languages supported as cloud_to_cloud servers
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700341_SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby', 'python']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700342
Jan Tattermusch320bd612015-09-15 12:44:35 -0700343_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch1f1c5c52015-10-09 14:36:28 -0700344 'empty_stream', 'client_streaming', 'server_streaming',
Jan Tattermusch13bf36a2015-10-14 17:01:00 -0700345 'cancel_after_begin', 'cancel_after_first_response',
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800346 'timeout_on_sleeping_server', 'custom_metadata',
347 'status_code_and_message', 'unimplemented_method',
348 'large_compressed_unary', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700349
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700350_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
351 'oauth2_auth_token', 'per_rpc_creds']
352
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800353_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700354
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700355DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
356
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700357def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
358 """Wraps given cmdline array to create 'docker run' cmdline from it."""
359 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
360
361 # turn environ into -e docker args
362 if environ:
363 for k,v in environ.iteritems():
364 docker_cmdline += ['-e', '%s=%s' % (k,v)]
365
366 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700367 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700368 if cwd:
369 workdir = os.path.join(workdir, cwd)
370 docker_cmdline += ['-w', workdir]
371
372 docker_cmdline += docker_args + [image] + cmdline
373 return docker_cmdline
374
375
376def bash_login_cmdline(cmdline):
377 """Creates bash -l -c cmdline from args list."""
378 # Use login shell:
379 # * rvm and nvm require it
380 # * makes error messages clearer if executables are missing
381 return ['bash', '-l', '-c', ' '.join(cmdline)]
382
383
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800384def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700385 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
386
387 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800388 cmdargs = []
389 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700390
391 # TODO(jtattermusch): this file path only works inside docker
392 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
393 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
394 key_file_arg = '--service_account_key_file=%s' % key_filepath
395 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
396
397 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700398 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700399 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
400 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800401 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700402
403 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800404 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700405
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700406 if test_case == 'oauth2_auth_token' and language == 'c++':
407 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800408 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700409
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700410 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800411 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700412
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800413 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700414
415
Jan Tattermusche2686282015-10-08 16:27:07 -0700416def _job_kill_handler(job):
417 if job._spec.container_name:
418 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700419 # When the job times out and we decide to kill it,
420 # we need to wait a before restarting the job
421 # to prevent "container name already in use" error.
422 # TODO(jtattermusch): figure out a cleaner way to to this.
423 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700424
425
murgatroid99090a2512016-02-19 11:32:31 -0800426def cloud_to_prod_jobspec(language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800427 server_host_detail, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700428 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800429 container_name = None
430 cmdargs = [
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800431 '--server_host=%s' % server_host_detail[0],
432 '--server_host_override=%s' % server_host_detail[1],
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700433 '--server_port=443',
434 '--use_tls=true',
435 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700436 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700437 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800438 auth_cmdargs, auth_env = auth_options(language, test_case)
439 cmdargs += auth_cmdargs
440 environ.update(auth_env)
441 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
442 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700443
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700444 if docker_image:
murgatroid99090a2512016-02-19 11:32:31 -0800445 container_name = dockerjob.random_name('interop_client_%s' %
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800446 language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700447 cmdline = docker_run_cmdline(cmdline,
448 image=docker_image,
449 cwd=cwd,
450 environ=environ,
451 docker_args=['--net=host',
452 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700453 cwd = None
454 environ = None
455
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700456 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700457 test_job = jobset.JobSpec(
458 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700459 cwd=cwd,
460 environ=environ,
murgatroid99090a2512016-02-19 11:32:31 -0800461 shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800462 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800463 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700464 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700465 timeout_retries=2 if args.allow_flakes else 0,
466 kill_handler=_job_kill_handler)
467 test_job.container_name = container_name
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700468 return test_job
469
Jan Tattermusch8266c672015-09-17 09:18:03 -0700470
471def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700472 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700473 """Creates jobspec for cloud-to-cloud interop test"""
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700474 cmdline = bash_login_cmdline(language.client_cmd([
475 '--server_host_override=foo.test.google.fr',
476 '--use_tls=true',
477 '--use_test_ca=true',
478 '--test_case=%s' % test_case,
479 '--server_host=%s' % server_host,
480 '--server_port=%s' % server_port]))
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700481 cwd = language.client_cwd
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700482 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700483 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700484 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700485 cmdline = docker_run_cmdline(cmdline,
486 image=docker_image,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700487 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700488 cwd=cwd,
Jan Tattermusche2686282015-10-08 16:27:07 -0700489 docker_args=['--net=host',
490 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700491 cwd = None
Jan Tattermusche2686282015-10-08 16:27:07 -0700492
Jan Tattermusch8266c672015-09-17 09:18:03 -0700493 test_job = jobset.JobSpec(
494 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700495 cwd=cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700496 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700497 shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800498 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800499 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700500 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700501 timeout_retries=2 if args.allow_flakes else 0,
502 kill_handler=_job_kill_handler)
503 test_job.container_name = container_name
Jan Tattermusch8266c672015-09-17 09:18:03 -0700504 return test_job
505
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700506
507def server_jobspec(language, docker_image):
508 """Create jobspec for running a server"""
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700509 container_name = dockerjob.random_name('interop_server_%s' % language.safename)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700510 cmdline = bash_login_cmdline(
511 language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700512 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700513 docker_cmdline = docker_run_cmdline(cmdline,
514 image=docker_image,
515 cwd=language.server_cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700516 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700517 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
Jan Tattermusche2686282015-10-08 16:27:07 -0700518 '--name', container_name])
Carl Mastrangelode449102015-10-28 11:05:49 -0700519
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700520 server_job = jobset.JobSpec(
521 cmdline=docker_cmdline,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700522 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700523 shortname='interop_server_%s' % language,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700524 timeout_seconds=30*60)
Jan Tattermusche2686282015-10-08 16:27:07 -0700525 server_job.container_name = container_name
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700526 return server_job
527
528
529def build_interop_image_jobspec(language, tag=None):
530 """Creates jobspec for building interop docker image for a language"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700531 if not tag:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700532 tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700533 env = {'INTEROP_IMAGE': tag,
534 'BASE_NAME': 'grpc_interop_%s' % language.safename}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700535 if not args.travis:
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700536 env['TTY_FLAG'] = '-t'
537 # This env variable is used to get around the github rate limit
538 # error when running the PHP `composer install` command
Stanley Cheungd82efd82016-02-10 10:36:20 -0800539 host_file = '%s/.composer/auth.json' % os.environ['HOME']
540 if language.safename == 'php' and os.path.exists(host_file):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700541 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Stanley Cheungd82efd82016-02-10 10:36:20 -0800542 '-v %s:/root/.composer/auth.json:ro' % host_file
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700543 build_job = jobset.JobSpec(
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700544 cmdline=['tools/run_tests/dockerize/build_interop_image.sh'],
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700545 environ=env,
Adele Zhoue4c35612015-10-16 15:34:23 -0700546 shortname='build_docker_%s' % (language),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700547 timeout_seconds=30*60)
548 build_job.tag = tag
549 return build_job
550
551
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800552def aggregate_http2_results(stdout):
553 match = re.search(r'\{"cases[^\]]*\]\}', stdout)
554 if not match:
555 return None
murgatroid99c3910ca2016-01-06 13:14:23 -0800556
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800557 results = json.loads(match.group(0))
558 skipped = 0
559 passed = 0
560 failed = 0
561 failed_cases = []
562 for case in results['cases']:
563 if case.get('skipped', False):
564 skipped += 1
565 else:
566 if case.get('passed', False):
567 passed += 1
568 else:
569 failed += 1
570 failed_cases.append(case.get('name', "NONAME"))
571 return {
572 'passed': passed,
573 'failed': failed,
574 'skipped': skipped,
575 'failed_cases': ', '.join(failed_cases),
576 'percent': 1.0 * passed / (passed + failed)
577 }
578
murgatroid99090a2512016-02-19 11:32:31 -0800579# A dictionary of prod servers to test.
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800580# Format: server_name: (server_host, server_host_override, errors_allowed)
581# TODO(adelez): implement logic for errors_allowed where if the indicated tests
582# fail, they don't impact the overall test result.
583prod_servers = {
murgatroid99090a2512016-02-19 11:32:31 -0800584 'default': ('grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800585 'grpc-test.sandbox.googleapis.com', False),
murgatroid99090a2512016-02-19 11:32:31 -0800586 'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800587 'grpc-test2.sandbox.googleapis.com', True),
murgatroid99090a2512016-02-19 11:32:31 -0800588 'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800589 False),
murgatroid99090a2512016-02-19 11:32:31 -0800590 'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
Adele Zhou2480f982016-02-26 14:18:46 -0800591 True),
murgatroid99e621f132016-04-21 14:28:00 -0700592 'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
593 'grpc-test4.sandbox.googleapis.com', True),
Adele Zhou2480f982016-02-26 14:18:46 -0800594 'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
595 True),
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800596}
597
Jan Tattermusch320bd612015-09-15 12:44:35 -0700598argp = argparse.ArgumentParser(description='Run interop tests.')
599argp.add_argument('-l', '--language',
600 choices=['all'] + sorted(_LANGUAGES),
601 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700602 default=['all'],
603 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700604argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700605argp.add_argument('--cloud_to_prod',
606 default=False,
607 action='store_const',
608 const=True,
609 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700610argp.add_argument('--cloud_to_prod_auth',
611 default=False,
612 action='store_const',
613 const=True,
614 help='Run cloud_to_prod_auth tests.')
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800615argp.add_argument('--prod_servers',
616 choices=prod_servers.keys(),
617 default=['default'],
618 nargs='+',
619 help=('The servers to run cloud_to_prod and '
620 'cloud_to_prod_auth tests against.'))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700621argp.add_argument('-s', '--server',
622 choices=['all'] + sorted(_SERVERS),
623 action='append',
624 help='Run cloud_to_cloud servers in a separate docker ' +
625 'image. Servers can only be started automatically if ' +
626 '--use_docker option is enabled.',
627 default=[])
628argp.add_argument('--override_server',
629 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700630 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700631 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
632 default=[])
633argp.add_argument('-t', '--travis',
634 default=False,
635 action='store_const',
636 const=True)
637argp.add_argument('--use_docker',
638 default=False,
639 action='store_const',
640 const=True,
641 help='Run all the interop tests under docker. That provides ' +
642 'additional isolation and prevents the need to install ' +
643 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700644argp.add_argument('--allow_flakes',
645 default=False,
646 action='store_const',
647 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700648 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700649argp.add_argument('--http2_interop',
650 default=False,
651 action='store_const',
652 const=True,
653 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800654
Jan Tattermusch320bd612015-09-15 12:44:35 -0700655args = argp.parse_args()
656
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700657servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700658 if x == 'all' else [x]
659 for x in args.server))
660
661if args.use_docker:
662 if not args.travis:
663 print 'Seen --use_docker flag, will run interop tests under docker.'
664 print
665 print 'IMPORTANT: The changes you are testing need to be locally committed'
666 print 'because only the committed changes in the current branch will be'
667 print 'copied to the docker environment.'
668 time.sleep(5)
669
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700670if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700671 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700672 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700673
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700674languages = set(_LANGUAGES[l]
675 for l in itertools.chain.from_iterable(
676 _LANGUAGES.iterkeys() if x == 'all' else [x]
677 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800678
Carl Mastrangelode449102015-10-28 11:05:49 -0700679http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700680
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700681docker_images={}
682if args.use_docker:
683 # languages for which to build docker images
684 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
685 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700686 if args.http2_interop:
687 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700688
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700689 build_jobs = []
690 for l in languages_to_build:
691 job = build_interop_image_jobspec(l)
692 docker_images[str(l)] = job.tag
693 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700694
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700695 if build_jobs:
696 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700697 num_failures, _ = jobset.run(
698 build_jobs, newline_on_success=True, maxjobs=args.jobs)
699 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800700 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700701 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700702 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800703 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700704 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700705 for image in docker_images.itervalues():
706 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700707 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700708
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700709# Start interop servers.
710server_jobs={}
711server_addresses={}
712try:
713 for s in servers:
714 lang = str(s)
715 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
716 job = dockerjob.DockerJob(spec)
717 server_jobs[lang] = job
718 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700719
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700720 jobs = []
721 if args.cloud_to_prod:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800722 for server_host_name in args.prod_servers:
723 for language in languages:
724 for test_case in _TEST_CASES:
725 if not test_case in language.unimplemented_test_cases():
726 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
727 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800728 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800729 prod_servers[server_host_name],
730 docker_image=docker_images.get(str(language)))
731 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800732
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800733 if args.http2_interop:
734 for test_case in _HTTP2_TEST_CASES:
735 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800736 http2Interop, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800737 prod_servers[server_host_name],
738 docker_image=docker_images.get(str(http2Interop)))
739 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700740
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700741 if args.cloud_to_prod_auth:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800742 for server_host_name in args.prod_servers:
743 for language in languages:
744 for test_case in _AUTH_TEST_CASES:
745 if not test_case in language.unimplemented_test_cases():
746 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800747 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800748 prod_servers[server_host_name],
749 docker_image=docker_images.get(str(language)), auth=True)
750 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700751
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700752 for server in args.override_server:
753 server_name = server[0]
754 (server_host, server_port) = server[1].split(':')
755 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700756
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700757 for server_name, server_address in server_addresses.iteritems():
758 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800759 server_language = _LANGUAGES.get(server_name, None)
760 skip_server = [] # test cases unimplemented by server
761 if server_language:
762 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700763 for language in languages:
764 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700765 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800766 if not test_case in skip_server:
767 test_job = cloud_to_cloud_jobspec(language,
768 test_case,
769 server_name,
770 server_host,
771 server_port,
772 docker_image=docker_images.get(str(language)))
773 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800774
Carl Mastrangelode449102015-10-28 11:05:49 -0700775 if args.http2_interop:
776 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800777 if server_name == "go":
778 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
murgatroid99c3910ca2016-01-06 13:14:23 -0800779 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700780 test_job = cloud_to_cloud_jobspec(http2Interop,
781 test_case,
782 server_name,
783 server_host,
784 server_port,
785 docker_image=docker_images.get(str(http2Interop)))
786 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700787
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700788 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700789 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700790 for image in docker_images.itervalues():
791 dockerjob.remove_image(image, skip_nonexistent=True)
792 sys.exit(1)
793
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800794 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700795 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700796 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700797 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700798 else:
799 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700800
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800801 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800802
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800803 for name, job in resultset.iteritems():
804 if "http2" in name:
805 job[0].http2results = aggregate_http2_results(job[0].message)
806
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800807 report_utils.render_interop_html_report(
murgatroid99c3910ca2016-01-06 13:14:23 -0800808 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700809 _HTTP2_TEST_CASES, resultset, num_failures,
murgatroid99090a2512016-02-19 11:32:31 -0800810 args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800811 args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700812
813finally:
814 # Check if servers are still running.
815 for server, job in server_jobs.iteritems():
816 if not job.is_running():
817 print 'Server "%s" has exited prematurely.' % server
818
819 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
820
821 for image in docker_images.itervalues():
822 print 'Removing docker image %s' % image
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800823 dockerjob.remove_image(image)