blob: f0935fb5d6140194f9905ba236fa3ba4a9886517 [file] [log] [blame]
Jan Tattermusch320bd612015-09-15 12:44:35 -07001#!/usr/bin/env python
2# Copyright 2015, Google Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Run interop (cross-language) tests in parallel."""
32
33import argparse
Jan Tattermusch91ad0182015-10-01 09:22:03 -070034import dockerjob
Jan Tattermusch320bd612015-09-15 12:44:35 -070035import itertools
36import xml.etree.cElementTree as ET
37import jobset
Jan Tattermusch210a0ea2015-10-02 15:05:36 -070038import multiprocessing
Jan Tattermusch8266c672015-09-17 09:18:03 -070039import os
40import subprocess
41import sys
Jan Tattermusch91ad0182015-10-01 09:22:03 -070042import tempfile
Jan Tattermusch8266c672015-09-17 09:18:03 -070043import time
Jan Tattermusch91ad0182015-10-01 09:22:03 -070044import uuid
Jan Tattermusch320bd612015-09-15 12:44:35 -070045
Jan Tattermusch91ad0182015-10-01 09:22:03 -070046ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
47os.chdir(ROOT)
48
49_DEFAULT_SERVER_PORT=8080
Jan Tattermuschf49936a2015-09-16 15:44:26 -070050
51_CLOUD_TO_PROD_BASE_ARGS = [
52 '--server_host_override=grpc-test.sandbox.google.com',
53 '--server_host=grpc-test.sandbox.google.com',
54 '--server_port=443']
55
Jan Tattermusch8266c672015-09-17 09:18:03 -070056_CLOUD_TO_CLOUD_BASE_ARGS = [
57 '--server_host_override=foo.test.google.fr']
58
Jan Tattermuschf49936a2015-09-16 15:44:26 -070059# TOOD(jtattermusch) wrapped languages use this variable for location
60# of roots.pem. We might want to use GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
61# supported by C core SslCredentials instead.
62_SSL_CERT_ENV = { 'SSL_CERT_FILE':'/usr/local/share/grpc/roots.pem' }
63
Jan Tattermuschcc1bde72015-10-05 12:47:45 -070064# TODO(jtattermusch) unify usage of --use_tls and --use_tls=true
65# TODO(jtattermusch) unify usage of --use_prod_roots and --use_test_ca
66# TODO(jtattermusch) go uses --tls_ca_file instead of --use_test_ca
Jan Tattermuschf49936a2015-09-16 15:44:26 -070067
Jan Tattermusch8266c672015-09-17 09:18:03 -070068
Jan Tattermuschf49936a2015-09-16 15:44:26 -070069class CXXLanguage:
70
71 def __init__(self):
72 self.client_cmdline_base = ['bins/opt/interop_client']
73 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -070074 self.server_cwd = None
Jan Tattermuschf49936a2015-09-16 15:44:26 -070075
76 def cloud_to_prod_args(self):
77 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
yang-g54db83d2015-10-01 11:42:05 -070078 ['--use_tls=true','--use_prod_roots'])
Jan Tattermuschf49936a2015-09-16 15:44:26 -070079
Jan Tattermusch8266c672015-09-17 09:18:03 -070080 def cloud_to_cloud_args(self):
81 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
yang-g54db83d2015-10-01 11:42:05 -070082 ['--use_tls=true'])
Jan Tattermusch8266c672015-09-17 09:18:03 -070083
Jan Tattermuschf49936a2015-09-16 15:44:26 -070084 def cloud_to_prod_env(self):
85 return None
86
Jan Tattermusch91ad0182015-10-01 09:22:03 -070087 def server_args(self):
Jan Tattermusch28bf5592015-10-02 13:50:24 -070088 return ['bins/opt/interop_server', '--use_tls=true']
Jan Tattermusch91ad0182015-10-01 09:22:03 -070089
Jan Tattermuschf49936a2015-09-16 15:44:26 -070090 def __str__(self):
91 return 'c++'
92
93
94class CSharpLanguage:
95
96 def __init__(self):
97 self.client_cmdline_base = ['mono', 'Grpc.IntegrationTesting.Client.exe']
98 self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug'
Jan Tattermusch91ad0182015-10-01 09:22:03 -070099 self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700100
101 def cloud_to_prod_args(self):
102 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
103 ['--use_tls'])
104
Jan Tattermusch8266c672015-09-17 09:18:03 -0700105 def cloud_to_cloud_args(self):
106 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
107 ['--use_tls', '--use_test_ca'])
108
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700109 def cloud_to_prod_env(self):
110 return _SSL_CERT_ENV
111
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700112 def server_args(self):
113 return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls']
114
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700115 def __str__(self):
116 return 'csharp'
117
118
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700119class JavaLanguage:
120
121 def __init__(self):
122 self.client_cmdline_base = ['./run-test-client.sh']
123 self.client_cwd = '../grpc-java'
124 self.server_cwd = '../grpc-java'
125
126 def cloud_to_prod_args(self):
127 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
128 ['--use_tls=true'])
129
130 def cloud_to_cloud_args(self):
131 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
132 ['--use_tls=true', '--use_test_ca=true'])
133
134 def cloud_to_prod_env(self):
135 return None
136
137 def server_args(self):
138 return ['./run-test-server.sh', '--use_tls=true']
139
140 def __str__(self):
141 return 'java'
142
143
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700144class GoLanguage:
145
146 def __init__(self):
147 self.client_cmdline_base = ['go', 'run', 'client.go']
148 # TODO: this relies on running inside docker
149 self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
150 self.server_cwd = '/go/src/google.golang.org/grpc/interop/server'
151
152 def cloud_to_prod_args(self):
153 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
154 ['--use_tls=true', '--tls_ca_file=""'])
155
156 def cloud_to_cloud_args(self):
157 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
158 ['--use_tls=true'])
159
160 def cloud_to_prod_env(self):
161 return None
162
163 def server_args(self):
164 return ['go', 'run', 'server.go', '--use_tls=true']
165
166 def __str__(self):
167 return 'go'
168
169
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700170class NodeLanguage:
171
172 def __init__(self):
173 self.client_cmdline_base = ['node', 'src/node/interop/interop_client.js']
174 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700175 self.server_cwd = None
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700176
177 def cloud_to_prod_args(self):
178 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
179 ['--use_tls=true'])
180
Jan Tattermusch8266c672015-09-17 09:18:03 -0700181 def cloud_to_cloud_args(self):
182 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
183 ['--use_tls=true', '--use_test_ca=true'])
184
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700185 def cloud_to_prod_env(self):
186 return _SSL_CERT_ENV
187
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700188 def server_args(self):
189 return ['node', 'src/node/interop/interop_server.js', '--use_tls=true']
190
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700191 def __str__(self):
192 return 'node'
193
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700194
195class PHPLanguage:
196
197 def __init__(self):
198 self.client_cmdline_base = ['src/php/bin/interop_client.sh']
199 self.client_cwd = None
200
201 def cloud_to_prod_args(self):
202 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
203 ['--use_tls'])
204
Jan Tattermusch8266c672015-09-17 09:18:03 -0700205 def cloud_to_cloud_args(self):
206 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
207 ['--use_tls', '--use_test_ca'])
208
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700209 def cloud_to_prod_env(self):
210 return _SSL_CERT_ENV
211
212 def __str__(self):
213 return 'php'
214
215
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700216class RubyLanguage:
217
218 def __init__(self):
219 self.client_cmdline_base = ['ruby', 'src/ruby/bin/interop/interop_client.rb']
220 self.client_cwd = None
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700221 self.server_cwd = None
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700222
223 def cloud_to_prod_args(self):
224 return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS +
225 ['--use_tls'])
226
Jan Tattermusch8266c672015-09-17 09:18:03 -0700227 def cloud_to_cloud_args(self):
228 return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS +
229 ['--use_tls', '--use_test_ca'])
230
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700231 def cloud_to_prod_env(self):
232 return _SSL_CERT_ENV
233
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700234 def server_args(self):
235 return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls']
236
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700237 def __str__(self):
238 return 'ruby'
239
240
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700241# TODO(jtattermusch): python once we get it working
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700242_LANGUAGES = {
243 'c++' : CXXLanguage(),
244 'csharp' : CSharpLanguage(),
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700245 'go' : GoLanguage(),
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700246 'java' : JavaLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700247 'node' : NodeLanguage(),
Jan Tattermuschf88f3e22015-09-16 17:50:45 -0700248 'php' : PHPLanguage(),
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700249 'ruby' : RubyLanguage(),
250}
Jan Tattermusch320bd612015-09-15 12:44:35 -0700251
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700252# languages supported as cloud_to_cloud servers
Jan Tattermusch8266c672015-09-17 09:18:03 -0700253# TODO(jtattermusch): enable other languages as servers as well
Jan Tattermuschcc1bde72015-10-05 12:47:45 -0700254_SERVERS = ['c++', 'node', 'csharp', 'java', 'go']
Jan Tattermusch8266c672015-09-17 09:18:03 -0700255
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700256# TODO(jtattermusch): add empty_stream once PHP starts supporting it.
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700257# TODO(jtattermusch): add timeout_on_sleeping_server once java starts supporting it.
Jan Tattermusch320bd612015-09-15 12:44:35 -0700258# TODO(jtattermusch): add support for auth tests.
259_TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700260 'client_streaming', 'server_streaming',
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700261 'cancel_after_begin', 'cancel_after_first_response']
Jan Tattermusch320bd612015-09-15 12:44:35 -0700262
Jan Tattermusch8266c672015-09-17 09:18:03 -0700263
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700264def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
265 """Wraps given cmdline array to create 'docker run' cmdline from it."""
266 docker_cmdline = ['docker', 'run', '-i', '--rm=true']
267
268 # turn environ into -e docker args
269 if environ:
270 for k,v in environ.iteritems():
271 docker_cmdline += ['-e', '%s=%s' % (k,v)]
272
273 # set working directory
274 workdir = '/var/local/git/grpc'
275 if cwd:
276 workdir = os.path.join(workdir, cwd)
277 docker_cmdline += ['-w', workdir]
278
279 docker_cmdline += docker_args + [image] + cmdline
280 return docker_cmdline
281
282
283def bash_login_cmdline(cmdline):
284 """Creates bash -l -c cmdline from args list."""
285 # Use login shell:
286 # * rvm and nvm require it
287 # * makes error messages clearer if executables are missing
288 return ['bash', '-l', '-c', ' '.join(cmdline)]
289
290
291def cloud_to_prod_jobspec(language, test_case, docker_image=None):
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700292 """Creates jobspec for cloud-to-prod interop test"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700293 cmdline = bash_login_cmdline(language.cloud_to_prod_args() +
294 ['--test_case=%s' % test_case])
295 cwd = language.client_cwd
296 environ = language.cloud_to_prod_env()
297 if docker_image:
298 cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, environ=environ)
299 cwd = None
300 environ = None
301
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700302 test_job = jobset.JobSpec(
303 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700304 cwd=cwd,
305 environ=environ,
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700306 shortname="cloud_to_prod:%s:%s" % (language, test_case),
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700307 timeout_seconds=2*60,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700308 flake_retries=5 if args.allow_flakes else 0,
309 timeout_retries=2 if args.allow_flakes else 0)
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700310 return test_job
311
Jan Tattermusch8266c672015-09-17 09:18:03 -0700312
313def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700314 server_port, docker_image=None):
Jan Tattermusch8266c672015-09-17 09:18:03 -0700315 """Creates jobspec for cloud-to-cloud interop test"""
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700316 cmdline = bash_login_cmdline(language.cloud_to_cloud_args() +
317 ['--test_case=%s' % test_case,
318 '--server_host=%s' % server_host,
319 '--server_port=%s' % server_port ])
320 cwd = language.client_cwd
321 if docker_image:
322 cmdline = docker_run_cmdline(cmdline,
323 image=docker_image,
324 cwd=cwd,
325 docker_args=['--net=host'])
326 cwd = None
Jan Tattermusch8266c672015-09-17 09:18:03 -0700327 test_job = jobset.JobSpec(
328 cmdline=cmdline,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700329 cwd=cwd,
Jan Tattermusch8266c672015-09-17 09:18:03 -0700330 shortname="cloud_to_cloud:%s:%s_server:%s" % (language, server_name,
331 test_case),
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700332 timeout_seconds=2*60,
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700333 flake_retries=5 if args.allow_flakes else 0,
334 timeout_retries=2 if args.allow_flakes else 0)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700335 return test_job
336
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700337
338def server_jobspec(language, docker_image):
339 """Create jobspec for running a server"""
340 cidfile = tempfile.mktemp()
341 cmdline = bash_login_cmdline(language.server_args() +
342 ['--port=%s' % _DEFAULT_SERVER_PORT])
343 docker_cmdline = docker_run_cmdline(cmdline,
344 image=docker_image,
345 cwd=language.server_cwd,
346 docker_args=['-p', str(_DEFAULT_SERVER_PORT),
347 '--cidfile', cidfile])
348 server_job = jobset.JobSpec(
349 cmdline=docker_cmdline,
350 shortname="interop_server:%s" % language,
351 timeout_seconds=30*60)
352 server_job.cidfile = cidfile
353 return server_job
354
355
356def build_interop_image_jobspec(language, tag=None):
357 """Creates jobspec for building interop docker image for a language"""
358 safelang = str(language).replace("+", "x")
359 if not tag:
360 tag = 'grpc_interop_%s:%s' % (safelang, uuid.uuid4())
361 env = {'INTEROP_IMAGE': tag, 'BASE_NAME': 'grpc_interop_%s' % safelang}
362 if not args.travis:
363 env['TTY_FLAG'] = '-t'
364 build_job = jobset.JobSpec(
365 cmdline=['tools/jenkins/build_interop_image.sh'],
366 environ=env,
367 shortname="build_docker_%s" % (language),
368 timeout_seconds=30*60)
369 build_job.tag = tag
370 return build_job
371
372
Jan Tattermusch320bd612015-09-15 12:44:35 -0700373argp = argparse.ArgumentParser(description='Run interop tests.')
374argp.add_argument('-l', '--language',
375 choices=['all'] + sorted(_LANGUAGES),
376 nargs='+',
Jan Tattermusch8266c672015-09-17 09:18:03 -0700377 default=['all'],
378 help='Clients to run.')
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700379argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700380argp.add_argument('--cloud_to_prod',
381 default=False,
382 action='store_const',
383 const=True,
384 help='Run cloud_to_prod tests.')
385argp.add_argument('-s', '--server',
386 choices=['all'] + sorted(_SERVERS),
387 action='append',
388 help='Run cloud_to_cloud servers in a separate docker ' +
389 'image. Servers can only be started automatically if ' +
390 '--use_docker option is enabled.',
391 default=[])
392argp.add_argument('--override_server',
393 action='append',
394 type=lambda kv: kv.split("="),
395 help='Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000',
396 default=[])
397argp.add_argument('-t', '--travis',
398 default=False,
399 action='store_const',
400 const=True)
401argp.add_argument('--use_docker',
402 default=False,
403 action='store_const',
404 const=True,
405 help='Run all the interop tests under docker. That provides ' +
406 'additional isolation and prevents the need to install ' +
407 'language specific prerequisites. Only available on Linux.')
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700408argp.add_argument('--allow_flakes',
409 default=False,
410 action='store_const',
411 const=True,
412 help="Allow flaky tests to show as passing (re-runs failed tests up to five times)")
Jan Tattermusch320bd612015-09-15 12:44:35 -0700413args = argp.parse_args()
414
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700415servers = set(s for s in itertools.chain.from_iterable(_SERVERS
Jan Tattermusch8266c672015-09-17 09:18:03 -0700416 if x == 'all' else [x]
417 for x in args.server))
418
419if args.use_docker:
420 if not args.travis:
421 print 'Seen --use_docker flag, will run interop tests under docker.'
422 print
423 print 'IMPORTANT: The changes you are testing need to be locally committed'
424 print 'because only the committed changes in the current branch will be'
425 print 'copied to the docker environment.'
426 time.sleep(5)
427
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700428if not args.use_docker and servers:
429 print "Running interop servers is only supported with --use_docker option enabled."
430 sys.exit(1)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700431
Jan Tattermuschf49936a2015-09-16 15:44:26 -0700432languages = set(_LANGUAGES[l]
433 for l in itertools.chain.from_iterable(
434 _LANGUAGES.iterkeys() if x == 'all' else [x]
435 for x in args.language))
Jan Tattermusch320bd612015-09-15 12:44:35 -0700436
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700437docker_images={}
438if args.use_docker:
439 # languages for which to build docker images
440 languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
441 [s for s in servers]))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700442
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700443 build_jobs = []
444 for l in languages_to_build:
445 job = build_interop_image_jobspec(l)
446 docker_images[str(l)] = job.tag
447 build_jobs.append(job)
Jan Tattermusch8266c672015-09-17 09:18:03 -0700448
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700449 if build_jobs:
450 jobset.message('START', 'Building interop docker images.', do_newline=True)
451 if jobset.run(build_jobs, newline_on_success=True, maxjobs=args.jobs):
452 jobset.message('SUCCESS', 'All docker images built successfully.', do_newline=True)
453 else:
454 jobset.message('FAILED', 'Failed to build interop docker images.', do_newline=True)
455 for image in docker_images.itervalues():
456 dockerjob.remove_image(image, skip_nonexistent=True)
457 exit(1);
Jan Tattermusch8266c672015-09-17 09:18:03 -0700458
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700459# Start interop servers.
460server_jobs={}
461server_addresses={}
462try:
463 for s in servers:
464 lang = str(s)
465 spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang))
466 job = dockerjob.DockerJob(spec)
467 server_jobs[lang] = job
468 server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
Jan Tattermusch8266c672015-09-17 09:18:03 -0700469
Jan Tattermusch210a0ea2015-10-02 15:05:36 -0700470
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700471 jobs = []
472 if args.cloud_to_prod:
473 for language in languages:
474 for test_case in _TEST_CASES:
475 test_job = cloud_to_prod_jobspec(language, test_case,
476 docker_image=docker_images.get(str(language)))
477 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700478
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700479 for server in args.override_server:
480 server_name = server[0]
481 (server_host, server_port) = server[1].split(':')
482 server_addresses[server_name] = (server_host, server_port)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700483
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700484 for server_name, server_address in server_addresses.iteritems():
485 (server_host, server_port) = server_address
486 for language in languages:
487 for test_case in _TEST_CASES:
488 test_job = cloud_to_cloud_jobspec(language,
489 test_case,
490 server_name,
491 server_host,
492 server_port,
493 docker_image=docker_images.get(str(language)))
494 jobs.append(test_job)
Jan Tattermusch320bd612015-09-15 12:44:35 -0700495
Jan Tattermusch91ad0182015-10-01 09:22:03 -0700496 if not jobs:
497 print "No jobs to run."
498 for image in docker_images.itervalues():
499 dockerjob.remove_image(image, skip_nonexistent=True)
500 sys.exit(1)
501
502 root = ET.Element('testsuites')
503 testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests')
504
505 if jobset.run(jobs, newline_on_success=True, maxjobs=args.jobs, xml_report=testsuite):
506 jobset.message('SUCCESS', 'All tests passed', do_newline=True)
507 else:
508 jobset.message('FAILED', 'Some tests failed', do_newline=True)
509
510 tree = ET.ElementTree(root)
511 tree.write('report.xml', encoding='UTF-8')
512
513finally:
514 # Check if servers are still running.
515 for server, job in server_jobs.iteritems():
516 if not job.is_running():
517 print 'Server "%s" has exited prematurely.' % server
518
519 dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
520
521 for image in docker_images.itervalues():
522 print 'Removing docker image %s' % image
523 dockerjob.remove_image(image)