From 98c0be52284bb6b4a8a4a3c32e5157a2d1f7776d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 9 Oct 2015 14:33:34 -0700 Subject: [PATCH 1/5] add retries for docker port command --- tools/run_tests/dockerjob.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py index 266edd4375b..0d4a1fc117e 100755 --- a/tools/run_tests/dockerjob.py +++ b/tools/run_tests/dockerjob.py @@ -49,10 +49,19 @@ def docker_kill(cid): return subprocess.call(['docker','kill', str(cid)]) == 0 -def docker_mapped_port(cid, port): +def docker_mapped_port(cid, port, timeout_seconds=15): """Get port mapped to internal given internal port for given container.""" - output = subprocess.check_output('docker port %s %s' % (cid, port), shell=True) - return int(output.split(':', 2)[1]) + started = time.time() + while time.time() - started < timeout_seconds: + try: + output = subprocess.check_output('docker port %s %s' % (cid, port), + stderr=_DEVNULL + shell=True) + return int(output.split(':', 2)[1]) + except subprocess.CalledProcessError as e: + pass + raise Exception('Failed to get exposed port %s for container %s.' % + (port, cid)) def finish_jobs(jobs): @@ -68,7 +77,7 @@ def image_exists(image): """Returns True if given docker image exists.""" return subprocess.call(['docker','inspect', image], stdout=_DEVNULL, - stderr=_DEVNULL) == 0 + stderr=subprocess.STDOUT) == 0 def remove_image(image, skip_nonexistent=False, max_retries=10): From 0a14f62e178f8557ed84b689ca6076b3c0372747 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 9 Oct 2015 14:34:29 -0700 Subject: [PATCH 2/5] dont use + character in generated container names --- tools/run_tests/run_interop_tests.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 4d09ae7fcda..dea33f7ab20 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -71,6 +71,7 @@ class CXXLanguage: self.client_cmdline_base = ['bins/opt/interop_client'] self.client_cwd = None self.server_cwd = None + self.safename = 'cxx' def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -96,6 +97,7 @@ class CSharpLanguage: self.client_cmdline_base = ['mono', 'Grpc.IntegrationTesting.Client.exe'] self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug' self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug' + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -121,6 +123,7 @@ class JavaLanguage: self.client_cmdline_base = ['./run-test-client.sh'] self.client_cwd = '../grpc-java' self.server_cwd = '../grpc-java' + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -147,6 +150,7 @@ class GoLanguage: # TODO: this relies on running inside docker self.client_cwd = '/go/src/google.golang.org/grpc/interop/client' self.server_cwd = '/go/src/google.golang.org/grpc/interop/server' + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -172,6 +176,7 @@ class NodeLanguage: self.client_cmdline_base = ['node', 'src/node/interop/interop_client.js'] self.client_cwd = None self.server_cwd = None + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -196,6 +201,7 @@ class PHPLanguage: def __init__(self): self.client_cmdline_base = ['src/php/bin/interop_client.sh'] self.client_cwd = None + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -218,6 +224,7 @@ class RubyLanguage: self.client_cmdline_base = ['ruby', 'src/ruby/bin/interop/interop_client.rb'] self.client_cwd = None self.server_cwd = None + self.safename = str(self) def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -337,7 +344,7 @@ def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False): cmdline = bash_login_cmdline(cmdline) if docker_image: - container_name = dockerjob.random_name('interop_client_%s' % language) + container_name = dockerjob.random_name('interop_client_%s' % language.safename) cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, @@ -370,7 +377,7 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host, '--server_port=%s' % server_port ]) cwd = language.client_cwd if docker_image: - container_name = dockerjob.random_name('interop_client_%s' % language) + container_name = dockerjob.random_name('interop_client_%s' % language.safename) cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, @@ -393,7 +400,7 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host, def server_jobspec(language, docker_image): """Create jobspec for running a server""" - container_name = dockerjob.random_name('interop_server_%s' % language) + container_name = dockerjob.random_name('interop_server_%s' % language.safename) cmdline = bash_login_cmdline(language.server_args() + ['--port=%s' % _DEFAULT_SERVER_PORT]) docker_cmdline = docker_run_cmdline(cmdline, @@ -411,10 +418,10 @@ def server_jobspec(language, docker_image): def build_interop_image_jobspec(language, tag=None): """Creates jobspec for building interop docker image for a language""" - safelang = str(language).replace("+", "x") if not tag: - tag = 'grpc_interop_%s:%s' % (safelang, uuid.uuid4()) - env = {'INTEROP_IMAGE': tag, 'BASE_NAME': 'grpc_interop_%s' % safelang} + tag = 'grpc_interop_%s:%s' % (language.safename, uuid.uuid4()) + env = {'INTEROP_IMAGE': tag, + 'BASE_NAME': 'grpc_interop_%s' % language.safename} if not args.travis: env['TTY_FLAG'] = '-t' build_job = jobset.JobSpec( From 1f1c5c541ad9b6c0d17085d3b18639563a5fb250 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 9 Oct 2015 14:36:28 -0700 Subject: [PATCH 3/5] run empty_stream interop test --- tools/run_tests/run_interop_tests.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index dea33f7ab20..6daa967bba4 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -258,11 +258,9 @@ _LANGUAGES = { # languages supported as cloud_to_cloud servers _SERVERS = ['c++', 'node', 'csharp', 'java', 'go', 'ruby'] -# TODO(jtattermusch): add empty_stream once PHP starts supporting it. # TODO(jtattermusch): add timeout_on_sleeping_server once java starts supporting it. -# TODO(jtattermusch): add support for auth tests. _TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong', - 'client_streaming', 'server_streaming', + 'empty_stream', 'client_streaming', 'server_streaming', 'cancel_after_begin', 'cancel_after_first_response'] _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds', From ab5bc721a099df03181fa6dc4ab06bff86a2d9d9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 9 Oct 2015 14:46:29 -0700 Subject: [PATCH 4/5] prevent polluting output by subprocesses --- tools/run_tests/dockerjob.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py index 0d4a1fc117e..6427b8e0220 100755 --- a/tools/run_tests/dockerjob.py +++ b/tools/run_tests/dockerjob.py @@ -55,7 +55,7 @@ def docker_mapped_port(cid, port, timeout_seconds=15): while time.time() - started < timeout_seconds: try: output = subprocess.check_output('docker port %s %s' % (cid, port), - stderr=_DEVNULL + stderr=_DEVNULL, shell=True) return int(output.split(':', 2)[1]) except subprocess.CalledProcessError as e: @@ -85,7 +85,9 @@ def remove_image(image, skip_nonexistent=False, max_retries=10): if skip_nonexistent and not image_exists(image): return True for attempt in range(0, max_retries): - if subprocess.call(['docker','rmi', '-f', image]) == 0: + if subprocess.call(['docker','rmi', '-f', image], + stdout=_DEVNULL, + stderr=subprocess.STDOUT) == 0: return True time.sleep(2) print 'Failed to remove docker image %s' % image From cc6a2b89fc88ec31972d0fb52f5d215d10747773 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 9 Oct 2015 14:53:51 -0700 Subject: [PATCH 5/5] eat output from docker kill as well --- tools/run_tests/dockerjob.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py index 6427b8e0220..1d67fe3033e 100755 --- a/tools/run_tests/dockerjob.py +++ b/tools/run_tests/dockerjob.py @@ -46,7 +46,9 @@ def random_name(base_name): def docker_kill(cid): """Kills a docker container. Returns True if successful.""" - return subprocess.call(['docker','kill', str(cid)]) == 0 + return subprocess.call(['docker','kill', str(cid)], + stdout=_DEVNULL, + stderr=subprocess.STDOUT) == 0 def docker_mapped_port(cid, port, timeout_seconds=15):