blob: d76dd4b7d26c3a4b3923f058f0c7daf5fda4df97 [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 Tattermusch9fc079f2016-06-21 19:53:31 -070057_SKIP_CLIENT_COMPRESSION = ['client_compressed_unary',
58 'client_compressed_streaming']
59
60_SKIP_SERVER_COMPRESSION = ['server_compressed_unary',
61 'server_compressed_streaming']
62
63_SKIP_COMPRESSION = _SKIP_CLIENT_COMPRESSION + _SKIP_SERVER_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080064
65_SKIP_ADVANCED = ['custom_metadata', 'status_code_and_message',
66 'unimplemented_method']
Jan Tattermusch8266c672015-09-17 09:18:03 -070067
Jan Tattermusch19f703d2016-03-03 15:33:29 -080068_TEST_TIMEOUT = 3*60
69
Jan Tattermuschf49936a2015-09-16 15:44:26 -070070class CXXLanguage:
71
72 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -070073 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -070074 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -070075 self.safename = 'cxx'
Jan Tattermuschf49936a2015-09-16 15:44:26 -070076
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070077 def client_cmd(self, args):
78 return ['bins/opt/interop_client'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -070079
Jan Tattermuschf49936a2015-09-16 15:44:26 -070080 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -070081 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -070082
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -070083 def server_cmd(self, args):
84 return ['bins/opt/interop_server', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -070085
Masood Malekghassemi18cc8422015-10-09 17:55:45 -070086 def global_env(self):
87 return {}
88
Jan Tattermusch289b7b92015-10-21 18:09:59 -070089 def unimplemented_test_cases(self):
David Garcia Quintas303d3082016-05-05 18:25:34 -070090 return _SKIP_ADVANCED
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080091
92 def unimplemented_test_cases_server(self):
David Garcia Quintas303d3082016-05-05 18:25:34 -070093 return _SKIP_ADVANCED
Jan Tattermusch289b7b92015-10-21 18:09:59 -070094
Jan Tattermuschf49936a2015-09-16 15:44:26 -070095 def __str__(self):
96 return 'c++'
97
98
99class CSharpLanguage:
100
101 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700102 self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700103 self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700104 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700105
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700106 def client_cmd(self, args):
107 return ['mono', 'Grpc.IntegrationTesting.Client.exe'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700108
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700109 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800110 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700111
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700112 def server_cmd(self, args):
113 return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700114
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700115 def global_env(self):
116 return {}
117
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700118 def unimplemented_test_cases(self):
Jan Tattermusch9fc079f2016-06-21 19:53:31 -0700119 return _SKIP_SERVER_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800120
121 def unimplemented_test_cases_server(self):
122 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700123
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700124 def __str__(self):
125 return 'csharp'
126
127
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700128class JavaLanguage:
129
130 def __init__(self):
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700131 self.client_cwd = '../grpc-java'
132 self.server_cwd = '../grpc-java'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700133 self.safename = str(self)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700134
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700135 def client_cmd(self, args):
136 return ['./run-test-client.sh'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700137
138 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700139 return {}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700140
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700141 def server_cmd(self, args):
142 return ['./run-test-server.sh', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700143
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700144 def global_env(self):
145 return {}
146
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700147 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800148 return _SKIP_ADVANCED + _SKIP_COMPRESSION
149
150 def unimplemented_test_cases_server(self):
151 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700152
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700153 def __str__(self):
154 return 'java'
155
156
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700157class GoLanguage:
158
159 def __init__(self):
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700160 # TODO: this relies on running inside docker
161 self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
162 self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700163 self.safename = str(self)
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700164
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700165 def client_cmd(self, args):
166 return ['go', 'run', 'client.go'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700167
168 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700169 return {}
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700170
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700171 def server_cmd(self, args):
172 return ['go', 'run', 'server.go', '--use_tls=true'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700173
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700174 def global_env(self):
175 return {}
176
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700177 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800178 return _SKIP_ADVANCED + _SKIP_COMPRESSION
179
180 def unimplemented_test_cases_server(self):
181 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700182
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700183 def __str__(self):
184 return 'go'
185
186
Carl Mastrangelode449102015-10-28 11:05:49 -0700187class Http2Client:
188 """Represents the HTTP/2 Interop Test
189
190 This pretends to be a language in order to be built and run, but really it
191 isn't.
192 """
193 def __init__(self):
194 self.client_cwd = None
195 self.safename = str(self)
196
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800197 def client_cmd(self, args):
198 return ['tools/http2_interop/http2_interop.test', '-test.v'] + args
Carl Mastrangelode449102015-10-28 11:05:49 -0700199
200 def cloud_to_prod_env(self):
201 return {}
202
203 def global_env(self):
204 return {}
205
206 def unimplemented_test_cases(self):
207 return _TEST_CASES
208
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800209 def unimplemented_test_cases_server(self):
210 return []
211
Carl Mastrangelode449102015-10-28 11:05:49 -0700212 def __str__(self):
213 return 'http2'
214
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700215class NodeLanguage:
216
217 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700218 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700219 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700220 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700221
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700222 def client_cmd(self, args):
223 return ['node', 'src/node/interop/interop_client.js'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700224
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700225 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800226 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700227
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700228 def server_cmd(self, args):
229 return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700230
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700231 def global_env(self):
232 return {}
233
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700234 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800235 return _SKIP_COMPRESSION
236
237 def unimplemented_test_cases_server(self):
238 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700239
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700240 def __str__(self):
241 return 'node'
242
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700243
244class PHPLanguage:
245
246 def __init__(self):
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700247 self.client_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700248 self.safename = str(self)
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700249
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700250 def client_cmd(self, args):
251 return ['src/php/bin/interop_client.sh'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700252
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700253 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800254 return {}
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700255
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700256 def global_env(self):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700257 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700258
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700259 def unimplemented_test_cases(self):
Stanley Cheung83d8e372016-06-17 11:53:33 -0700260 return _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800261
262 def unimplemented_test_cases_server(self):
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700263 return []
264
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700265 def __str__(self):
266 return 'php'
267
268
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700269class RubyLanguage:
270
271 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700272 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700273 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700274 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700275
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700276 def client_cmd(self, args):
murgatroid99e621f132016-04-21 14:28:00 -0700277 return ['ruby', 'src/ruby/pb/test/client.rb'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700278
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700279 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800280 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700281
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700282 def server_cmd(self, args):
murgatroid99e621f132016-04-21 14:28:00 -0700283 return ['ruby', 'src/ruby/pb/test/server.rb', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700284
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700285 def global_env(self):
286 return {}
287
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700288 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800289 return _SKIP_ADVANCED + _SKIP_COMPRESSION
290
291 def unimplemented_test_cases_server(self):
292 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700293
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700294 def __str__(self):
295 return 'ruby'
296
297
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700298class PythonLanguage:
299
300 def __init__(self):
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700301 self.client_cwd = None
302 self.server_cwd = None
303 self.safename = str(self)
304
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700305 def client_cmd(self, args):
306 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800307 'tox -einterop_client --',
308 ' '.join(args)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700309 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700310
311 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800312 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700313
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700314 def server_cmd(self, args):
315 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800316 'tox -einterop_server --',
317 ' '.join(args) + ' --use_tls=true'
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700318 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700319
320 def global_env(self):
Ken Payson707c9e22016-04-20 09:42:19 -0700321 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT),
322 'PYTHONPATH': '{}/src/python/gens'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700323
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700324 def unimplemented_test_cases(self):
Ken Payson22a65e12016-06-07 19:06:05 -0700325 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800326
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',
David Garcia Quintasff32a862016-06-21 17:07:20 -0700353 'client_compressed_unary', 'server_compressed_unary',
354 'client_compressed_streaming', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700355
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700356_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
357 'oauth2_auth_token', 'per_rpc_creds']
358
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800359_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700360
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700361DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
362
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700363def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
364 """Wraps given cmdline array to create 'docker run' cmdline from it."""
365 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
366
367 # turn environ into -e docker args
368 if environ:
369 for k,v in environ.iteritems():
370 docker_cmdline += ['-e', '%s=%s' % (k,v)]
371
372 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700373 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700374 if cwd:
375 workdir = os.path.join(workdir, cwd)
376 docker_cmdline += ['-w', workdir]
377
378 docker_cmdline += docker_args + [image] + cmdline
379 return docker_cmdline
380
381
382def bash_login_cmdline(cmdline):
383 """Creates bash -l -c cmdline from args list."""
384 # Use login shell:
385 # * rvm and nvm require it
386 # * makes error messages clearer if executables are missing
387 return ['bash', '-l', '-c', ' '.join(cmdline)]
388
389
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800390def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700391 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
392
393 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800394 cmdargs = []
395 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700396
397 # TODO(jtattermusch): this file path only works inside docker
398 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
399 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
400 key_file_arg = '--service_account_key_file=%s' % key_filepath
401 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
402
403 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700404 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700405 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
406 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800407 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700408
409 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800410 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700411
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700412 if test_case == 'oauth2_auth_token' and language == 'c++':
413 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800414 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700415
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700416 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800417 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700418
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800419 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700420
421
Jan Tattermusche2686282015-10-08 16:27:07 -0700422def _job_kill_handler(job):
423 if job._spec.container_name:
424 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700425 # When the job times out and we decide to kill it,
426 # we need to wait a before restarting the job
427 # to prevent "container name already in use" error.
428 # TODO(jtattermusch): figure out a cleaner way to to this.
429 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700430
431
murgatroid99090a2512016-02-19 11:32:31 -0800432def cloud_to_prod_jobspec(language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800433 server_host_detail, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700434 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800435 container_name = None
436 cmdargs = [
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800437 '--server_host=%s' % server_host_detail[0],
438 '--server_host_override=%s' % server_host_detail[1],
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700439 '--server_port=443',
440 '--use_tls=true',
441 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700442 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700443 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800444 auth_cmdargs, auth_env = auth_options(language, test_case)
445 cmdargs += auth_cmdargs
446 environ.update(auth_env)
447 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
448 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700449
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700450 if docker_image:
murgatroid99090a2512016-02-19 11:32:31 -0800451 container_name = dockerjob.random_name('interop_client_%s' %
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800452 language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700453 cmdline = docker_run_cmdline(cmdline,
454 image=docker_image,
455 cwd=cwd,
456 environ=environ,
457 docker_args=['--net=host',
458 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700459 cwd = None
460 environ = None
461
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700462 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700463 test_job = jobset.JobSpec(
464 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700465 cwd=cwd,
466 environ=environ,
murgatroid99090a2512016-02-19 11:32:31 -0800467 shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800468 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800469 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700470 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700471 timeout_retries=2 if args.allow_flakes else 0,
472 kill_handler=_job_kill_handler)
473 test_job.container_name = container_name
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700474 return test_job
475
Jan Tattermusch8266c672015-09-17 09:18:03 -0700476
477def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700478 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700479 """Creates jobspec for cloud-to-cloud interop test"""
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700480 cmdline = bash_login_cmdline(language.client_cmd([
481 '--server_host_override=foo.test.google.fr',
482 '--use_tls=true',
483 '--use_test_ca=true',
484 '--test_case=%s' % test_case,
485 '--server_host=%s' % server_host,
486 '--server_port=%s' % server_port]))
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700487 cwd = language.client_cwd
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700488 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700489 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700490 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700491 cmdline = docker_run_cmdline(cmdline,
492 image=docker_image,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700493 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700494 cwd=cwd,
Jan Tattermusche2686282015-10-08 16:27:07 -0700495 docker_args=['--net=host',
496 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700497 cwd = None
Jan Tattermusche2686282015-10-08 16:27:07 -0700498
Jan Tattermusch8266c672015-09-17 09:18:03 -0700499 test_job = jobset.JobSpec(
500 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700501 cwd=cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700502 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700503 shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800504 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800505 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700506 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700507 timeout_retries=2 if args.allow_flakes else 0,
508 kill_handler=_job_kill_handler)
509 test_job.container_name = container_name
Jan Tattermusch8266c672015-09-17 09:18:03 -0700510 return test_job
511
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700512
513def server_jobspec(language, docker_image):
514 """Create jobspec for running a server"""
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700515 container_name = dockerjob.random_name('interop_server_%s' % language.safename)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700516 cmdline = bash_login_cmdline(
517 language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700518 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700519 docker_cmdline = docker_run_cmdline(cmdline,
520 image=docker_image,
521 cwd=language.server_cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700522 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700523 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
Jan Tattermusche2686282015-10-08 16:27:07 -0700524 '--name', container_name])
Carl Mastrangelode449102015-10-28 11:05:49 -0700525
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700526 server_job = jobset.JobSpec(
527 cmdline=docker_cmdline,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700528 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700529 shortname='interop_server_%s' % language,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700530 timeout_seconds=30*60)
Jan Tattermusche2686282015-10-08 16:27:07 -0700531 server_job.container_name = container_name
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700532 return server_job
533
534
535def build_interop_image_jobspec(language, tag=None):
536 """Creates jobspec for building interop docker image for a language"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700537 if not tag:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700538 tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700539 env = {'INTEROP_IMAGE': tag,
540 'BASE_NAME': 'grpc_interop_%s' % language.safename}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700541 if not args.travis:
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700542 env['TTY_FLAG'] = '-t'
543 # This env variable is used to get around the github rate limit
544 # error when running the PHP `composer install` command
Stanley Cheungd82efd82016-02-10 10:36:20 -0800545 host_file = '%s/.composer/auth.json' % os.environ['HOME']
546 if language.safename == 'php' and os.path.exists(host_file):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700547 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Stanley Cheungd82efd82016-02-10 10:36:20 -0800548 '-v %s:/root/.composer/auth.json:ro' % host_file
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700549 build_job = jobset.JobSpec(
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700550 cmdline=['tools/run_tests/dockerize/build_interop_image.sh'],
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700551 environ=env,
Adele Zhoue4c35612015-10-16 15:34:23 -0700552 shortname='build_docker_%s' % (language),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700553 timeout_seconds=30*60)
554 build_job.tag = tag
555 return build_job
556
557
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800558def aggregate_http2_results(stdout):
559 match = re.search(r'\{"cases[^\]]*\]\}', stdout)
560 if not match:
561 return None
murgatroid99c3910ca2016-01-06 13:14:23 -0800562
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800563 results = json.loads(match.group(0))
564 skipped = 0
565 passed = 0
566 failed = 0
567 failed_cases = []
568 for case in results['cases']:
569 if case.get('skipped', False):
570 skipped += 1
571 else:
572 if case.get('passed', False):
573 passed += 1
574 else:
575 failed += 1
576 failed_cases.append(case.get('name', "NONAME"))
577 return {
578 'passed': passed,
579 'failed': failed,
580 'skipped': skipped,
581 'failed_cases': ', '.join(failed_cases),
582 'percent': 1.0 * passed / (passed + failed)
583 }
584
murgatroid99090a2512016-02-19 11:32:31 -0800585# A dictionary of prod servers to test.
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800586# Format: server_name: (server_host, server_host_override, errors_allowed)
587# TODO(adelez): implement logic for errors_allowed where if the indicated tests
588# fail, they don't impact the overall test result.
589prod_servers = {
murgatroid99090a2512016-02-19 11:32:31 -0800590 'default': ('grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800591 'grpc-test.sandbox.googleapis.com', False),
murgatroid99090a2512016-02-19 11:32:31 -0800592 'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800593 'grpc-test2.sandbox.googleapis.com', True),
murgatroid99090a2512016-02-19 11:32:31 -0800594 'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800595 False),
murgatroid99090a2512016-02-19 11:32:31 -0800596 'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
Adele Zhou2480f982016-02-26 14:18:46 -0800597 True),
murgatroid99e621f132016-04-21 14:28:00 -0700598 'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
599 'grpc-test4.sandbox.googleapis.com', True),
Adele Zhou2480f982016-02-26 14:18:46 -0800600 'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
601 True),
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800602}
603
Jan Tattermusch320bd612015-09-15 12:44:35 -0700604argp = argparse.ArgumentParser(description='Run interop tests.')
605argp.add_argument('-l', '--language',
606 choices=['all'] + sorted(_LANGUAGES),
607 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700608 default=['all'],
609 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700610argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700611argp.add_argument('--cloud_to_prod',
612 default=False,
613 action='store_const',
614 const=True,
615 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700616argp.add_argument('--cloud_to_prod_auth',
617 default=False,
618 action='store_const',
619 const=True,
620 help='Run cloud_to_prod_auth tests.')
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800621argp.add_argument('--prod_servers',
622 choices=prod_servers.keys(),
623 default=['default'],
624 nargs='+',
625 help=('The servers to run cloud_to_prod and '
626 'cloud_to_prod_auth tests against.'))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700627argp.add_argument('-s', '--server',
628 choices=['all'] + sorted(_SERVERS),
629 action='append',
630 help='Run cloud_to_cloud servers in a separate docker ' +
631 'image. Servers can only be started automatically if ' +
632 '--use_docker option is enabled.',
633 default=[])
634argp.add_argument('--override_server',
635 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700636 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700637 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
638 default=[])
639argp.add_argument('-t', '--travis',
640 default=False,
641 action='store_const',
642 const=True)
643argp.add_argument('--use_docker',
644 default=False,
645 action='store_const',
646 const=True,
647 help='Run all the interop tests under docker. That provides ' +
648 'additional isolation and prevents the need to install ' +
649 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700650argp.add_argument('--allow_flakes',
651 default=False,
652 action='store_const',
653 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700654 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700655argp.add_argument('--http2_interop',
656 default=False,
657 action='store_const',
658 const=True,
659 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800660
Jan Tattermusch320bd612015-09-15 12:44:35 -0700661args = argp.parse_args()
662
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700663servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700664 if x == 'all' else [x]
665 for x in args.server))
666
667if args.use_docker:
668 if not args.travis:
669 print 'Seen --use_docker flag, will run interop tests under docker.'
670 print
671 print 'IMPORTANT: The changes you are testing need to be locally committed'
672 print 'because only the committed changes in the current branch will be'
673 print 'copied to the docker environment.'
674 time.sleep(5)
675
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700676if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700677 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700678 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700679
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700680languages = set(_LANGUAGES[l]
681 for l in itertools.chain.from_iterable(
682 _LANGUAGES.iterkeys() if x == 'all' else [x]
683 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800684
Carl Mastrangelode449102015-10-28 11:05:49 -0700685http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700686
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700687docker_images={}
688if args.use_docker:
689 # languages for which to build docker images
690 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
691 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700692 if args.http2_interop:
693 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700694
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700695 build_jobs = []
696 for l in languages_to_build:
697 job = build_interop_image_jobspec(l)
698 docker_images[str(l)] = job.tag
699 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700700
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700701 if build_jobs:
702 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700703 num_failures, _ = jobset.run(
704 build_jobs, newline_on_success=True, maxjobs=args.jobs)
705 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800706 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700707 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700708 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800709 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700710 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700711 for image in docker_images.itervalues():
712 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700713 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700714
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700715# Start interop servers.
716server_jobs={}
717server_addresses={}
718try:
719 for s in servers:
720 lang = str(s)
721 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
722 job = dockerjob.DockerJob(spec)
723 server_jobs[lang] = job
724 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700725
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700726 jobs = []
727 if args.cloud_to_prod:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800728 for server_host_name in args.prod_servers:
729 for language in languages:
730 for test_case in _TEST_CASES:
731 if not test_case in language.unimplemented_test_cases():
732 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
733 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800734 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800735 prod_servers[server_host_name],
736 docker_image=docker_images.get(str(language)))
737 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800738
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800739 if args.http2_interop:
740 for test_case in _HTTP2_TEST_CASES:
741 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800742 http2Interop, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800743 prod_servers[server_host_name],
744 docker_image=docker_images.get(str(http2Interop)))
745 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700746
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700747 if args.cloud_to_prod_auth:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800748 for server_host_name in args.prod_servers:
749 for language in languages:
750 for test_case in _AUTH_TEST_CASES:
751 if not test_case in language.unimplemented_test_cases():
752 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800753 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800754 prod_servers[server_host_name],
755 docker_image=docker_images.get(str(language)), auth=True)
756 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700757
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700758 for server in args.override_server:
759 server_name = server[0]
760 (server_host, server_port) = server[1].split(':')
761 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700762
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700763 for server_name, server_address in server_addresses.iteritems():
764 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800765 server_language = _LANGUAGES.get(server_name, None)
766 skip_server = [] # test cases unimplemented by server
767 if server_language:
768 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700769 for language in languages:
770 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700771 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800772 if not test_case in skip_server:
773 test_job = cloud_to_cloud_jobspec(language,
774 test_case,
775 server_name,
776 server_host,
777 server_port,
778 docker_image=docker_images.get(str(language)))
779 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800780
Carl Mastrangelode449102015-10-28 11:05:49 -0700781 if args.http2_interop:
782 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800783 if server_name == "go":
784 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
murgatroid99c3910ca2016-01-06 13:14:23 -0800785 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700786 test_job = cloud_to_cloud_jobspec(http2Interop,
787 test_case,
788 server_name,
789 server_host,
790 server_port,
791 docker_image=docker_images.get(str(http2Interop)))
792 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700793
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700794 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700795 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700796 for image in docker_images.itervalues():
797 dockerjob.remove_image(image, skip_nonexistent=True)
798 sys.exit(1)
799
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800800 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700801 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700802 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700803 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700804 else:
805 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700806
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800807 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800808
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800809 for name, job in resultset.iteritems():
810 if "http2" in name:
811 job[0].http2results = aggregate_http2_results(job[0].message)
812
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800813 report_utils.render_interop_html_report(
murgatroid99c3910ca2016-01-06 13:14:23 -0800814 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700815 _HTTP2_TEST_CASES, resultset, num_failures,
murgatroid99090a2512016-02-19 11:32:31 -0800816 args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800817 args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700818
819finally:
820 # Check if servers are still running.
821 for server, job in server_jobs.iteritems():
822 if not job.is_running():
823 print 'Server "%s" has exited prematurely.' % server
824
825 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
826
827 for image in docker_images.itervalues():
828 print 'Removing docker image %s' % image
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800829 dockerjob.remove_image(image)