blob: fb2be22944dfc32c7c0f74e4c1701d43d9e28618 [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):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -080085 return _SKIP_ADVANCED + _SKIP_COMPRESSION
86
87 def unimplemented_test_cases_server(self):
88 return _SKIP_ADVANCED + _SKIP_COMPRESSION
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 Tattermuscha86b41e2015-12-10 08:00:28 -0800114 # TODO: status_code_and_message doesn't work against node_server
115 return _SKIP_COMPRESSION + ['status_code_and_message']
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800116
117 def unimplemented_test_cases_server(self):
118 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700119
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700120 def __str__(self):
121 return 'csharp'
122
123
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700124class JavaLanguage:
125
126 def __init__(self):
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700127 self.client_cwd = '../grpc-java'
128 self.server_cwd = '../grpc-java'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700129 self.safename = str(self)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700130
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700131 def client_cmd(self, args):
132 return ['./run-test-client.sh'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700133
134 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700135 return {}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700136
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700137 def server_cmd(self, args):
138 return ['./run-test-server.sh', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700139
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700140 def global_env(self):
141 return {}
142
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700143 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800144 return _SKIP_ADVANCED + _SKIP_COMPRESSION
145
146 def unimplemented_test_cases_server(self):
147 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700148
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700149 def __str__(self):
150 return 'java'
151
152
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700153class GoLanguage:
154
155 def __init__(self):
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700156 # TODO: this relies on running inside docker
157 self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
158 self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700159 self.safename = str(self)
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700160
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700161 def client_cmd(self, args):
162 return ['go', 'run', 'client.go'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700163
164 def cloud_to_prod_env(self):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700165 return {}
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700166
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700167 def server_cmd(self, args):
168 return ['go', 'run', 'server.go', '--use_tls=true'] + args
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700169
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700170 def global_env(self):
171 return {}
172
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700173 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800174 return _SKIP_ADVANCED + _SKIP_COMPRESSION
175
176 def unimplemented_test_cases_server(self):
177 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700178
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700179 def __str__(self):
180 return 'go'
181
182
Carl Mastrangelode449102015-10-28 11:05:49 -0700183class Http2Client:
184 """Represents the HTTP/2 Interop Test
185
186 This pretends to be a language in order to be built and run, but really it
187 isn't.
188 """
189 def __init__(self):
190 self.client_cwd = None
191 self.safename = str(self)
192
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800193 def client_cmd(self, args):
194 return ['tools/http2_interop/http2_interop.test', '-test.v'] + args
Carl Mastrangelode449102015-10-28 11:05:49 -0700195
196 def cloud_to_prod_env(self):
197 return {}
198
199 def global_env(self):
200 return {}
201
202 def unimplemented_test_cases(self):
203 return _TEST_CASES
204
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800205 def unimplemented_test_cases_server(self):
206 return []
207
Carl Mastrangelode449102015-10-28 11:05:49 -0700208 def __str__(self):
209 return 'http2'
210
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700211class NodeLanguage:
212
213 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700214 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700215 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700216 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700217
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700218 def client_cmd(self, args):
219 return ['node', 'src/node/interop/interop_client.js'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700220
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700221 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800222 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700223
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700224 def server_cmd(self, args):
225 return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700226
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700227 def global_env(self):
228 return {}
229
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700230 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800231 return _SKIP_COMPRESSION
232
233 def unimplemented_test_cases_server(self):
234 return _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700235
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700236 def __str__(self):
237 return 'node'
238
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700239
240class PHPLanguage:
241
242 def __init__(self):
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700243 self.client_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700244 self.safename = str(self)
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700245
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700246 def client_cmd(self, args):
247 return ['src/php/bin/interop_client.sh'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700248
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700249 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800250 return {}
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700251
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700252 def global_env(self):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700253 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700254
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700255 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800256 return _SKIP_ADVANCED + _SKIP_COMPRESSION
257
258 def unimplemented_test_cases_server(self):
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700259 return []
260
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700261 def __str__(self):
262 return 'php'
263
264
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700265class RubyLanguage:
266
267 def __init__(self):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700268 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700269 self.server_cwd = None
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700270 self.safename = str(self)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700271
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700272 def client_cmd(self, args):
273 return ['ruby', 'src/ruby/bin/interop/interop_client.rb'] + args
Jan Tattermusch8266c672015-09-17 09:18:03 -0700274
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700275 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800276 return {}
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700277
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700278 def server_cmd(self, args):
279 return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls=true'] + args
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700280
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700281 def global_env(self):
282 return {}
283
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700284 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800285 return _SKIP_ADVANCED + _SKIP_COMPRESSION
286
287 def unimplemented_test_cases_server(self):
288 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700289
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700290 def __str__(self):
291 return 'ruby'
292
293
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700294class PythonLanguage:
295
296 def __init__(self):
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700297 self.client_cwd = None
298 self.server_cwd = None
299 self.safename = str(self)
300
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700301 def client_cmd(self, args):
302 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800303 'tox -einterop_client --',
304 ' '.join(args)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700305 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700306
307 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800308 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700309
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700310 def server_cmd(self, args):
311 return [
Masood Malekghassemiccc16102015-12-17 14:32:44 -0800312 'tox -einterop_server --',
313 ' '.join(args) + ' --use_tls=true'
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700314 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700315
316 def global_env(self):
Ken Payson707c9e22016-04-20 09:42:19 -0700317 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT),
318 'PYTHONPATH': '{}/src/python/gens'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700319
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700320 def unimplemented_test_cases(self):
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800321 return _SKIP_ADVANCED + _SKIP_COMPRESSION + ['jwt_token_creds',
322 'per_rpc_creds']
323
324 def unimplemented_test_cases_server(self):
325 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700326
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700327 def __str__(self):
328 return 'python'
329
330
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700331_LANGUAGES = {
332 'c++' : CXXLanguage(),
333 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700334 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700335 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700336 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700337 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700338 'ruby' : RubyLanguage(),
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700339 'python' : PythonLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700340}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700341
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700342# languages supported as cloud_to_cloud servers
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700343_SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby', 'python']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700344
Jan Tattermusch320bd612015-09-15 12:44:35 -0700345_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch1f1c5c52015-10-09 14:36:28 -0700346 'empty_stream', 'client_streaming', 'server_streaming',
Jan Tattermusch13bf36a2015-10-14 17:01:00 -0700347 'cancel_after_begin', 'cancel_after_first_response',
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800348 'timeout_on_sleeping_server', 'custom_metadata',
349 'status_code_and_message', 'unimplemented_method',
350 'large_compressed_unary', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700351
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700352_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
353 'oauth2_auth_token', 'per_rpc_creds']
354
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800355_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700356
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700357DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
358
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700359def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
360 """Wraps given cmdline array to create 'docker run' cmdline from it."""
361 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
362
363 # turn environ into -e docker args
364 if environ:
365 for k,v in environ.iteritems():
366 docker_cmdline += ['-e', '%s=%s' % (k,v)]
367
368 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700369 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700370 if cwd:
371 workdir = os.path.join(workdir, cwd)
372 docker_cmdline += ['-w', workdir]
373
374 docker_cmdline += docker_args + [image] + cmdline
375 return docker_cmdline
376
377
378def bash_login_cmdline(cmdline):
379 """Creates bash -l -c cmdline from args list."""
380 # Use login shell:
381 # * rvm and nvm require it
382 # * makes error messages clearer if executables are missing
383 return ['bash', '-l', '-c', ' '.join(cmdline)]
384
385
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800386def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700387 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
388
389 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800390 cmdargs = []
391 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700392
393 # TODO(jtattermusch): this file path only works inside docker
394 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
395 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
396 key_file_arg = '--service_account_key_file=%s' % key_filepath
397 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
398
399 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700400 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700401 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
402 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800403 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700404
405 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800406 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700407
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700408 if test_case == 'oauth2_auth_token' and language == 'c++':
409 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800410 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700411
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700412 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800413 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700414
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800415 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700416
417
Jan Tattermusche2686282015-10-08 16:27:07 -0700418def _job_kill_handler(job):
419 if job._spec.container_name:
420 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700421 # When the job times out and we decide to kill it,
422 # we need to wait a before restarting the job
423 # to prevent "container name already in use" error.
424 # TODO(jtattermusch): figure out a cleaner way to to this.
425 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700426
427
murgatroid99090a2512016-02-19 11:32:31 -0800428def cloud_to_prod_jobspec(language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800429 server_host_detail, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700430 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800431 container_name = None
432 cmdargs = [
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800433 '--server_host=%s' % server_host_detail[0],
434 '--server_host_override=%s' % server_host_detail[1],
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700435 '--server_port=443',
436 '--use_tls=true',
437 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700438 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700439 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800440 auth_cmdargs, auth_env = auth_options(language, test_case)
441 cmdargs += auth_cmdargs
442 environ.update(auth_env)
443 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
444 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700445
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700446 if docker_image:
murgatroid99090a2512016-02-19 11:32:31 -0800447 container_name = dockerjob.random_name('interop_client_%s' %
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800448 language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700449 cmdline = docker_run_cmdline(cmdline,
450 image=docker_image,
451 cwd=cwd,
452 environ=environ,
453 docker_args=['--net=host',
454 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700455 cwd = None
456 environ = None
457
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700458 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700459 test_job = jobset.JobSpec(
460 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700461 cwd=cwd,
462 environ=environ,
murgatroid99090a2512016-02-19 11:32:31 -0800463 shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800464 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800465 timeout_seconds=_TEST_TIMEOUT,
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,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800500 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800501 timeout_seconds=_TEST_TIMEOUT,
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
Stanley Cheungd82efd82016-02-10 10:36:20 -0800541 host_file = '%s/.composer/auth.json' % os.environ['HOME']
542 if language.safename == 'php' and os.path.exists(host_file):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700543 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Stanley Cheungd82efd82016-02-10 10:36:20 -0800544 '-v %s:/root/.composer/auth.json:ro' % host_file
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
murgatroid99c3910ca2016-01-06 13:14:23 -0800558
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800559 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
murgatroid99090a2512016-02-19 11:32:31 -0800581# A dictionary of prod servers to test.
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800582# Format: server_name: (server_host, server_host_override, errors_allowed)
583# TODO(adelez): implement logic for errors_allowed where if the indicated tests
584# fail, they don't impact the overall test result.
585prod_servers = {
murgatroid99090a2512016-02-19 11:32:31 -0800586 'default': ('grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800587 'grpc-test.sandbox.googleapis.com', False),
murgatroid99090a2512016-02-19 11:32:31 -0800588 'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800589 'grpc-test2.sandbox.googleapis.com', True),
murgatroid99090a2512016-02-19 11:32:31 -0800590 'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800591 False),
murgatroid99090a2512016-02-19 11:32:31 -0800592 'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
Adele Zhou2480f982016-02-26 14:18:46 -0800593 True),
594 'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
595 'grpc-test4.sandbox.googleapis.com', True),
596 'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
597 True),
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800598}
599
Jan Tattermusch320bd612015-09-15 12:44:35 -0700600argp = argparse.ArgumentParser(description='Run interop tests.')
601argp.add_argument('-l', '--language',
602 choices=['all'] + sorted(_LANGUAGES),
603 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700604 default=['all'],
605 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700606argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700607argp.add_argument('--cloud_to_prod',
608 default=False,
609 action='store_const',
610 const=True,
611 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700612argp.add_argument('--cloud_to_prod_auth',
613 default=False,
614 action='store_const',
615 const=True,
616 help='Run cloud_to_prod_auth tests.')
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800617argp.add_argument('--prod_servers',
618 choices=prod_servers.keys(),
619 default=['default'],
620 nargs='+',
621 help=('The servers to run cloud_to_prod and '
622 'cloud_to_prod_auth tests against.'))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700623argp.add_argument('-s', '--server',
624 choices=['all'] + sorted(_SERVERS),
625 action='append',
626 help='Run cloud_to_cloud servers in a separate docker ' +
627 'image. Servers can only be started automatically if ' +
628 '--use_docker option is enabled.',
629 default=[])
630argp.add_argument('--override_server',
631 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700632 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700633 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
634 default=[])
635argp.add_argument('-t', '--travis',
636 default=False,
637 action='store_const',
638 const=True)
639argp.add_argument('--use_docker',
640 default=False,
641 action='store_const',
642 const=True,
643 help='Run all the interop tests under docker. That provides ' +
644 'additional isolation and prevents the need to install ' +
645 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700646argp.add_argument('--allow_flakes',
647 default=False,
648 action='store_const',
649 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700650 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700651argp.add_argument('--http2_interop',
652 default=False,
653 action='store_const',
654 const=True,
655 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800656
Jan Tattermusch320bd612015-09-15 12:44:35 -0700657args = argp.parse_args()
658
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700659servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700660 if x == 'all' else [x]
661 for x in args.server))
662
663if args.use_docker:
664 if not args.travis:
665 print 'Seen --use_docker flag, will run interop tests under docker.'
666 print
667 print 'IMPORTANT: The changes you are testing need to be locally committed'
668 print 'because only the committed changes in the current branch will be'
669 print 'copied to the docker environment.'
670 time.sleep(5)
671
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700672if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700673 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700674 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700675
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700676languages = set(_LANGUAGES[l]
677 for l in itertools.chain.from_iterable(
678 _LANGUAGES.iterkeys() if x == 'all' else [x]
679 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800680
Carl Mastrangelode449102015-10-28 11:05:49 -0700681http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700682
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700683docker_images={}
684if args.use_docker:
685 # languages for which to build docker images
686 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
687 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700688 if args.http2_interop:
689 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700690
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700691 build_jobs = []
692 for l in languages_to_build:
693 job = build_interop_image_jobspec(l)
694 docker_images[str(l)] = job.tag
695 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700696
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700697 if build_jobs:
698 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700699 num_failures, _ = jobset.run(
700 build_jobs, newline_on_success=True, maxjobs=args.jobs)
701 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800702 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700703 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700704 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800705 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700706 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700707 for image in docker_images.itervalues():
708 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700709 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700710
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700711# Start interop servers.
712server_jobs={}
713server_addresses={}
714try:
715 for s in servers:
716 lang = str(s)
717 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
718 job = dockerjob.DockerJob(spec)
719 server_jobs[lang] = job
720 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700721
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700722 jobs = []
723 if args.cloud_to_prod:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800724 for server_host_name in args.prod_servers:
725 for language in languages:
726 for test_case in _TEST_CASES:
727 if not test_case in language.unimplemented_test_cases():
728 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
729 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800730 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800731 prod_servers[server_host_name],
732 docker_image=docker_images.get(str(language)))
733 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800734
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800735 if args.http2_interop:
736 for test_case in _HTTP2_TEST_CASES:
737 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800738 http2Interop, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800739 prod_servers[server_host_name],
740 docker_image=docker_images.get(str(http2Interop)))
741 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700742
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700743 if args.cloud_to_prod_auth:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800744 for server_host_name in args.prod_servers:
745 for language in languages:
746 for test_case in _AUTH_TEST_CASES:
747 if not test_case in language.unimplemented_test_cases():
748 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800749 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800750 prod_servers[server_host_name],
751 docker_image=docker_images.get(str(language)), auth=True)
752 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700753
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700754 for server in args.override_server:
755 server_name = server[0]
756 (server_host, server_port) = server[1].split(':')
757 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700758
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700759 for server_name, server_address in server_addresses.iteritems():
760 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800761 server_language = _LANGUAGES.get(server_name, None)
762 skip_server = [] # test cases unimplemented by server
763 if server_language:
764 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700765 for language in languages:
766 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700767 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800768 if not test_case in skip_server:
769 test_job = cloud_to_cloud_jobspec(language,
770 test_case,
771 server_name,
772 server_host,
773 server_port,
774 docker_image=docker_images.get(str(language)))
775 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800776
Carl Mastrangelode449102015-10-28 11:05:49 -0700777 if args.http2_interop:
778 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800779 if server_name == "go":
780 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
murgatroid99c3910ca2016-01-06 13:14:23 -0800781 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700782 test_job = cloud_to_cloud_jobspec(http2Interop,
783 test_case,
784 server_name,
785 server_host,
786 server_port,
787 docker_image=docker_images.get(str(http2Interop)))
788 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700789
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700790 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700791 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700792 for image in docker_images.itervalues():
793 dockerjob.remove_image(image, skip_nonexistent=True)
794 sys.exit(1)
795
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800796 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700797 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700798 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700799 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700800 else:
801 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700802
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800803 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800804
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800805 for name, job in resultset.iteritems():
806 if "http2" in name:
807 job[0].http2results = aggregate_http2_results(job[0].message)
808
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800809 report_utils.render_interop_html_report(
murgatroid99c3910ca2016-01-06 13:14:23 -0800810 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700811 _HTTP2_TEST_CASES, resultset, num_failures,
murgatroid99090a2512016-02-19 11:32:31 -0800812 args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800813 args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700814
815finally:
816 # Check if servers are still running.
817 for server, job in server_jobs.iteritems():
818 if not job.is_running():
819 print 'Server "%s" has exited prematurely.' % server
820
821 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
822
823 for image in docker_images.itervalues():
824 print 'Removing docker image %s' % image
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800825 dockerjob.remove_image(image)