blob: 13a4a49325a5738ede679932e3a050f3d03fcd6d [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 Malekghassemi3b5b2062016-06-02 20:27:20 -0700307 'py27/bin/python',
308 'src/python/grpcio_tests/setup.py',
309 'run_interop',
310 '--client',
311 '--args="{}"'.format(' '.join(args))
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700312 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700313
314 def cloud_to_prod_env(self):
Jan Tattermuscha6b2c4c2015-12-10 16:41:11 -0800315 return {}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700316
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700317 def server_cmd(self, args):
318 return [
Masood Malekghassemi3b5b2062016-06-02 20:27:20 -0700319 'py27/bin/python',
320 'src/python/grpcio_tests/setup.py',
321 'run_interop',
322 '--server',
323 '--args="{}"'.format(' '.join(args) + ' --use_tls=true')
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700324 ]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700325
326 def global_env(self):
Ken Payson707c9e22016-04-20 09:42:19 -0700327 return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT),
328 'PYTHONPATH': '{}/src/python/gens'.format(DOCKER_WORKDIR_ROOT)}
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700329
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700330 def unimplemented_test_cases(self):
Ken Payson22a65e12016-06-07 19:06:05 -0700331 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800332
333 def unimplemented_test_cases_server(self):
334 return _SKIP_ADVANCED + _SKIP_COMPRESSION
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700335
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700336 def __str__(self):
337 return 'python'
338
339
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700340_LANGUAGES = {
341 'c++' : CXXLanguage(),
342 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700343 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700344 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700345 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700346 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700347 'ruby' : RubyLanguage(),
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700348 'python' : PythonLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700349}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700350
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700351# languages supported as cloud_to_cloud servers
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700352_SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby', 'python']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700353
Jan Tattermusch320bd612015-09-15 12:44:35 -0700354_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch1f1c5c52015-10-09 14:36:28 -0700355 'empty_stream', 'client_streaming', 'server_streaming',
Jan Tattermusch13bf36a2015-10-14 17:01:00 -0700356 'cancel_after_begin', 'cancel_after_first_response',
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800357 'timeout_on_sleeping_server', 'custom_metadata',
358 'status_code_and_message', 'unimplemented_method',
David Garcia Quintasff32a862016-06-21 17:07:20 -0700359 'client_compressed_unary', 'server_compressed_unary',
360 'client_compressed_streaming', 'server_compressed_streaming']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700361
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700362_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
363 'oauth2_auth_token', 'per_rpc_creds']
364
Carl Mastrangelo2dd55db2015-11-19 10:51:48 -0800365_HTTP2_TEST_CASES = ["tls", "framing"]
Jan Tattermusch8266c672015-09-17 09:18:03 -0700366
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700367DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
368
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700369def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
370 """Wraps given cmdline array to create 'docker run' cmdline from it."""
371 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
372
373 # turn environ into -e docker args
374 if environ:
375 for k,v in environ.iteritems():
376 docker_cmdline += ['-e', '%s=%s' % (k,v)]
377
378 # set working directory
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700379 workdir = DOCKER_WORKDIR_ROOT
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700380 if cwd:
381 workdir = os.path.join(workdir, cwd)
382 docker_cmdline += ['-w', workdir]
383
384 docker_cmdline += docker_args + [image] + cmdline
385 return docker_cmdline
386
387
388def bash_login_cmdline(cmdline):
389 """Creates bash -l -c cmdline from args list."""
390 # Use login shell:
391 # * rvm and nvm require it
392 # * makes error messages clearer if executables are missing
393 return ['bash', '-l', '-c', ' '.join(cmdline)]
394
395
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800396def auth_options(language, test_case):
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700397 """Returns (cmdline, env) tuple with cloud_to_prod_auth test options."""
398
399 language = str(language)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800400 cmdargs = []
401 env = {}
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700402
403 # TODO(jtattermusch): this file path only works inside docker
404 key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
405 oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
406 key_file_arg = '--service_account_key_file=%s' % key_filepath
407 default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
408
409 if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
Jan Tattermusch3b6fef12015-10-19 19:33:24 -0700410 if language in ['csharp', 'node', 'php', 'python', 'ruby']:
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700411 env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
412 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800413 cmdargs += [key_file_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700414
415 if test_case in ['per_rpc_creds', 'oauth2_auth_token']:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800416 cmdargs += [oauth_scope_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700417
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700418 if test_case == 'oauth2_auth_token' and language == 'c++':
419 # C++ oauth2 test uses GCE creds and thus needs to know the default account
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800420 cmdargs += [default_account_arg]
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700421
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700422 if test_case == 'compute_engine_creds':
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800423 cmdargs += [oauth_scope_arg, default_account_arg]
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700424
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800425 return (cmdargs, env)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700426
427
Jan Tattermusche2686282015-10-08 16:27:07 -0700428def _job_kill_handler(job):
429 if job._spec.container_name:
430 dockerjob.docker_kill(job._spec.container_name)
Jan Tattermusch39e3cb32015-10-22 18:21:08 -0700431 # When the job times out and we decide to kill it,
432 # we need to wait a before restarting the job
433 # to prevent "container name already in use" error.
434 # TODO(jtattermusch): figure out a cleaner way to to this.
435 time.sleep(2)
Jan Tattermusche2686282015-10-08 16:27:07 -0700436
437
murgatroid99090a2512016-02-19 11:32:31 -0800438def cloud_to_prod_jobspec(language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800439 server_host_detail, docker_image=None, auth=False):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700440 """Creates jobspec for cloud-to-prod interop test"""
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800441 container_name = None
442 cmdargs = [
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800443 '--server_host=%s' % server_host_detail[0],
444 '--server_host_override=%s' % server_host_detail[1],
Jan Tattermuschc8b94412015-10-21 17:57:28 -0700445 '--server_port=443',
446 '--use_tls=true',
447 '--test_case=%s' % test_case]
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700448 environ = dict(language.cloud_to_prod_env(), **language.global_env())
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700449 if auth:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800450 auth_cmdargs, auth_env = auth_options(language, test_case)
451 cmdargs += auth_cmdargs
452 environ.update(auth_env)
453 cmdline = bash_login_cmdline(language.client_cmd(cmdargs))
454 cwd = language.client_cwd
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700455
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700456 if docker_image:
murgatroid99090a2512016-02-19 11:32:31 -0800457 container_name = dockerjob.random_name('interop_client_%s' %
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800458 language.safename)
Jan Tattermusche2686282015-10-08 16:27:07 -0700459 cmdline = docker_run_cmdline(cmdline,
460 image=docker_image,
461 cwd=cwd,
462 environ=environ,
463 docker_args=['--net=host',
464 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700465 cwd = None
466 environ = None
467
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700468 suite_name='cloud_to_prod_auth' if auth else 'cloud_to_prod'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700469 test_job = jobset.JobSpec(
470 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700471 cwd=cwd,
472 environ=environ,
murgatroid99090a2512016-02-19 11:32:31 -0800473 shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800474 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800475 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700476 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700477 timeout_retries=2 if args.allow_flakes else 0,
478 kill_handler=_job_kill_handler)
murgatroid9901467562016-06-27 15:48:08 -0700479 if docker_image:
480 test_job.container_name = container_name
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700481 return test_job
482
Jan Tattermusch8266c672015-09-17 09:18:03 -0700483
484def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700485 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700486 """Creates jobspec for cloud-to-cloud interop test"""
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700487 cmdline = bash_login_cmdline(language.client_cmd([
488 '--server_host_override=foo.test.google.fr',
489 '--use_tls=true',
490 '--use_test_ca=true',
491 '--test_case=%s' % test_case,
492 '--server_host=%s' % server_host,
493 '--server_port=%s' % server_port]))
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700494 cwd = language.client_cwd
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700495 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700496 if docker_image:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700497 container_name = dockerjob.random_name('interop_client_%s' % language.safename)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700498 cmdline = docker_run_cmdline(cmdline,
499 image=docker_image,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700500 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700501 cwd=cwd,
Jan Tattermusche2686282015-10-08 16:27:07 -0700502 docker_args=['--net=host',
503 '--name', container_name])
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700504 cwd = None
Jan Tattermusche2686282015-10-08 16:27:07 -0700505
Jan Tattermusch8266c672015-09-17 09:18:03 -0700506 test_job = jobset.JobSpec(
507 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700508 cwd=cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700509 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700510 shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800511 test_case),
Jan Tattermusch19f703d2016-03-03 15:33:29 -0800512 timeout_seconds=_TEST_TIMEOUT,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700513 flake_retries=5 if args.allow_flakes else 0,
Jan Tattermusche2686282015-10-08 16:27:07 -0700514 timeout_retries=2 if args.allow_flakes else 0,
515 kill_handler=_job_kill_handler)
murgatroid9901467562016-06-27 15:48:08 -0700516 if docker_image:
517 test_job.container_name = container_name
Jan Tattermusch8266c672015-09-17 09:18:03 -0700518 return test_job
519
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700520
521def server_jobspec(language, docker_image):
522 """Create jobspec for running a server"""
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700523 container_name = dockerjob.random_name('interop_server_%s' % language.safename)
Masood Malekghassemi7566c9a2015-10-21 20:29:23 -0700524 cmdline = bash_login_cmdline(
525 language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700526 environ = language.global_env()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700527 docker_cmdline = docker_run_cmdline(cmdline,
528 image=docker_image,
529 cwd=language.server_cwd,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700530 environ=environ,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700531 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
Jan Tattermusche2686282015-10-08 16:27:07 -0700532 '--name', container_name])
Carl Mastrangelode449102015-10-28 11:05:49 -0700533
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700534 server_job = jobset.JobSpec(
535 cmdline=docker_cmdline,
Masood Malekghassemi18cc8422015-10-09 17:55:45 -0700536 environ=environ,
Adele Zhoue4c35612015-10-16 15:34:23 -0700537 shortname='interop_server_%s' % language,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700538 timeout_seconds=30*60)
Jan Tattermusche2686282015-10-08 16:27:07 -0700539 server_job.container_name = container_name
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700540 return server_job
541
542
543def build_interop_image_jobspec(language, tag=None):
544 """Creates jobspec for building interop docker image for a language"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700545 if not tag:
Jan Tattermusch0a14f622015-10-09 14:34:29 -0700546 tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4())
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700547 env = {'INTEROP_IMAGE': tag,
548 'BASE_NAME': 'grpc_interop_%s' % language.safename}
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700549 if not args.travis:
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700550 env['TTY_FLAG'] = '-t'
551 # This env variable is used to get around the github rate limit
552 # error when running the PHP `composer install` command
Stanley Cheungd82efd82016-02-10 10:36:20 -0800553 host_file = '%s/.composer/auth.json' % os.environ['HOME']
554 if language.safename == 'php' and os.path.exists(host_file):
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700555 env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
Stanley Cheungd82efd82016-02-10 10:36:20 -0800556 '-v %s:/root/.composer/auth.json:ro' % host_file
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700557 build_job = jobset.JobSpec(
Jan Tattermusch9835d4b2016-04-29 15:05:05 -0700558 cmdline=['tools/run_tests/dockerize/build_interop_image.sh'],
Stanley Cheung22b6bed2015-10-15 16:54:52 -0700559 environ=env,
Adele Zhoue4c35612015-10-16 15:34:23 -0700560 shortname='build_docker_%s' % (language),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700561 timeout_seconds=30*60)
562 build_job.tag = tag
563 return build_job
564
565
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800566def aggregate_http2_results(stdout):
567 match = re.search(r'\{"cases[^\]]*\]\}', stdout)
568 if not match:
569 return None
murgatroid99c3910ca2016-01-06 13:14:23 -0800570
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800571 results = json.loads(match.group(0))
572 skipped = 0
573 passed = 0
574 failed = 0
575 failed_cases = []
576 for case in results['cases']:
577 if case.get('skipped', False):
578 skipped += 1
579 else:
580 if case.get('passed', False):
581 passed += 1
582 else:
583 failed += 1
584 failed_cases.append(case.get('name', "NONAME"))
585 return {
586 'passed': passed,
587 'failed': failed,
588 'skipped': skipped,
589 'failed_cases': ', '.join(failed_cases),
590 'percent': 1.0 * passed / (passed + failed)
591 }
592
murgatroid99090a2512016-02-19 11:32:31 -0800593# A dictionary of prod servers to test.
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800594# Format: server_name: (server_host, server_host_override, errors_allowed)
595# TODO(adelez): implement logic for errors_allowed where if the indicated tests
596# fail, they don't impact the overall test result.
597prod_servers = {
murgatroid99090a2512016-02-19 11:32:31 -0800598 'default': ('grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800599 'grpc-test.sandbox.googleapis.com', False),
murgatroid99090a2512016-02-19 11:32:31 -0800600 'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800601 'grpc-test2.sandbox.googleapis.com', True),
murgatroid99090a2512016-02-19 11:32:31 -0800602 'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800603 False),
murgatroid99090a2512016-02-19 11:32:31 -0800604 'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
Adele Zhou2480f982016-02-26 14:18:46 -0800605 True),
murgatroid99e621f132016-04-21 14:28:00 -0700606 'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
607 'grpc-test4.sandbox.googleapis.com', True),
Adele Zhou2480f982016-02-26 14:18:46 -0800608 'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
609 True),
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800610}
611
Jan Tattermusch320bd612015-09-15 12:44:35 -0700612argp = argparse.ArgumentParser(description='Run interop tests.')
613argp.add_argument('-l', '--language',
614 choices=['all'] + sorted(_LANGUAGES),
615 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700616 default=['all'],
617 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700618argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700619argp.add_argument('--cloud_to_prod',
620 default=False,
621 action='store_const',
622 const=True,
623 help='Run cloud_to_prod tests.')
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700624argp.add_argument('--cloud_to_prod_auth',
625 default=False,
626 action='store_const',
627 const=True,
628 help='Run cloud_to_prod_auth tests.')
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800629argp.add_argument('--prod_servers',
630 choices=prod_servers.keys(),
631 default=['default'],
632 nargs='+',
633 help=('The servers to run cloud_to_prod and '
634 'cloud_to_prod_auth tests against.'))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700635argp.add_argument('-s', '--server',
636 choices=['all'] + sorted(_SERVERS),
637 action='append',
638 help='Run cloud_to_cloud servers in a separate docker ' +
639 'image. Servers can only be started automatically if ' +
640 '--use_docker option is enabled.',
641 default=[])
642argp.add_argument('--override_server',
643 action='append',
Adele Zhoue4c35612015-10-16 15:34:23 -0700644 type=lambda kv: kv.split('='),
Jan Tattermusch8266c672015-09-17 09:18:03 -0700645 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
646 default=[])
647argp.add_argument('-t', '--travis',
648 default=False,
649 action='store_const',
650 const=True)
651argp.add_argument('--use_docker',
652 default=False,
653 action='store_const',
654 const=True,
655 help='Run all the interop tests under docker. That provides ' +
656 'additional isolation and prevents the need to install ' +
657 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700658argp.add_argument('--allow_flakes',
659 default=False,
660 action='store_const',
661 const=True,
Adele Zhoue4c35612015-10-16 15:34:23 -0700662 help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
Carl Mastrangelode449102015-10-28 11:05:49 -0700663argp.add_argument('--http2_interop',
664 default=False,
665 action='store_const',
666 const=True,
667 help='Enable HTTP/2 interop tests')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800668
Jan Tattermusch320bd612015-09-15 12:44:35 -0700669args = argp.parse_args()
670
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700671servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700672 if x == 'all' else [x]
673 for x in args.server))
674
675if args.use_docker:
676 if not args.travis:
677 print 'Seen --use_docker flag, will run interop tests under docker.'
678 print
679 print 'IMPORTANT: The changes you are testing need to be locally committed'
680 print 'because only the committed changes in the current branch will be'
681 print 'copied to the docker environment.'
682 time.sleep(5)
683
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700684if not args.use_docker and servers:
Adele Zhoue4c35612015-10-16 15:34:23 -0700685 print 'Running interop servers is only supported with --use_docker option enabled.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700686 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700687
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700688languages = set(_LANGUAGES[l]
689 for l in itertools.chain.from_iterable(
690 _LANGUAGES.iterkeys() if x == 'all' else [x]
691 for x in args.language))
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800692
Carl Mastrangelode449102015-10-28 11:05:49 -0700693http2Interop = Http2Client() if args.http2_interop else None
Jan Tattermusch320bd612015-09-15 12:44:35 -0700694
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700695docker_images={}
696if args.use_docker:
697 # languages for which to build docker images
698 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
699 [s for s in servers]))
Carl Mastrangelode449102015-10-28 11:05:49 -0700700 if args.http2_interop:
701 languages_to_build.add(http2Interop)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700702
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700703 build_jobs = []
704 for l in languages_to_build:
705 job = build_interop_image_jobspec(l)
706 docker_images[str(l)] = job.tag
707 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700708
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700709 if build_jobs:
710 jobset.message('START', 'Building interop docker images.', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700711 num_failures, _ = jobset.run(
712 build_jobs, newline_on_success=True, maxjobs=args.jobs)
713 if num_failures == 0:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800714 jobset.message('SUCCESS', 'All docker images built successfully.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700715 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700716 else:
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800717 jobset.message('FAILED', 'Failed to build interop docker images.',
Adele Zhoue4c35612015-10-16 15:34:23 -0700718 do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700719 for image in docker_images.itervalues():
720 dockerjob.remove_image(image, skip_nonexistent=True)
Carl Mastrangelo7a171402015-10-26 14:01:03 -0700721 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700722
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700723# Start interop servers.
724server_jobs={}
725server_addresses={}
726try:
727 for s in servers:
728 lang = str(s)
729 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
730 job = dockerjob.DockerJob(spec)
731 server_jobs[lang] = job
732 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700733
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700734 jobs = []
735 if args.cloud_to_prod:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800736 for server_host_name in args.prod_servers:
737 for language in languages:
738 for test_case in _TEST_CASES:
739 if not test_case in language.unimplemented_test_cases():
740 if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
741 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800742 language, 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(language)))
745 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800746
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800747 if args.http2_interop:
748 for test_case in _HTTP2_TEST_CASES:
749 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800750 http2Interop, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800751 prod_servers[server_host_name],
752 docker_image=docker_images.get(str(http2Interop)))
753 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700754
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700755 if args.cloud_to_prod_auth:
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800756 for server_host_name in args.prod_servers:
757 for language in languages:
758 for test_case in _AUTH_TEST_CASES:
759 if not test_case in language.unimplemented_test_cases():
760 test_job = cloud_to_prod_jobspec(
murgatroid99090a2512016-02-19 11:32:31 -0800761 language, test_case, server_host_name,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800762 prod_servers[server_host_name],
763 docker_image=docker_images.get(str(language)), auth=True)
764 jobs.append(test_job)
Jan Tattermuschfb8c77d2015-10-06 09:33:37 -0700765
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700766 for server in args.override_server:
767 server_name = server[0]
768 (server_host, server_port) = server[1].split(':')
769 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700770
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700771 for server_name, server_address in server_addresses.iteritems():
772 (server_host, server_port) = server_address
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800773 server_language = _LANGUAGES.get(server_name, None)
774 skip_server = [] # test cases unimplemented by server
775 if server_language:
776 skip_server = server_language.unimplemented_test_cases_server()
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700777 for language in languages:
778 for test_case in _TEST_CASES:
Jan Tattermusch289b7b92015-10-21 18:09:59 -0700779 if not test_case in language.unimplemented_test_cases():
Jan Tattermusch5c7a1c82015-12-09 19:56:51 -0800780 if not test_case in skip_server:
781 test_job = cloud_to_cloud_jobspec(language,
782 test_case,
783 server_name,
784 server_host,
785 server_port,
786 docker_image=docker_images.get(str(language)))
787 jobs.append(test_job)
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800788
Carl Mastrangelode449102015-10-28 11:05:49 -0700789 if args.http2_interop:
790 for test_case in _HTTP2_TEST_CASES:
Carl Mastrangelo3b2e1bd2015-11-06 14:31:55 -0800791 if server_name == "go":
792 # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
murgatroid99c3910ca2016-01-06 13:14:23 -0800793 continue
Carl Mastrangelode449102015-10-28 11:05:49 -0700794 test_job = cloud_to_cloud_jobspec(http2Interop,
795 test_case,
796 server_name,
797 server_host,
798 server_port,
799 docker_image=docker_images.get(str(http2Interop)))
800 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700801
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700802 if not jobs:
Adele Zhoue4c35612015-10-16 15:34:23 -0700803 print 'No jobs to run.'
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700804 for image in docker_images.itervalues():
805 dockerjob.remove_image(image, skip_nonexistent=True)
806 sys.exit(1)
807
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800808 num_failures, resultset = jobset.run(jobs, newline_on_success=True,
Adele Zhou2271ab52015-10-28 13:59:14 -0700809 maxjobs=args.jobs)
Adele Zhoue4c35612015-10-16 15:34:23 -0700810 if num_failures:
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700811 jobset.message('FAILED', 'Some tests failed', do_newline=True)
Adele Zhoue4c35612015-10-16 15:34:23 -0700812 else:
813 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700814
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800815 report_utils.render_junit_xml_report(resultset, 'report.xml')
Masood Malekghassemi0a9cc3c2015-11-09 12:24:05 -0800816
Carl Mastrangeloe7f8e8e2015-12-08 17:22:44 -0800817 for name, job in resultset.iteritems():
818 if "http2" in name:
819 job[0].http2results = aggregate_http2_results(job[0].message)
820
Adele Zhou3bc7ba42015-11-05 10:21:58 -0800821 report_utils.render_interop_html_report(
murgatroid99c3910ca2016-01-06 13:14:23 -0800822 set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
Carl Mastrangelode449102015-10-28 11:05:49 -0700823 _HTTP2_TEST_CASES, resultset, num_failures,
murgatroid99090a2512016-02-19 11:32:31 -0800824 args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers,
Adele Zhoub9e66cc2016-02-03 13:12:23 -0800825 args.http2_interop)
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700826
827finally:
828 # Check if servers are still running.
829 for server, job in server_jobs.iteritems():
830 if not job.is_running():
831 print 'Server "%s" has exited prematurely.' % server
832
833 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
834
835 for image in docker_images.itervalues():
836 print 'Removing docker image %s' % image
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800837 dockerjob.remove_image(image)