From 8426329120a4a0abaf46c68abf35e53515149995 Mon Sep 17 00:00:00 2001 From: Alex Polcyn Date: Wed, 15 Nov 2017 00:32:50 +0000 Subject: Apply patches to ruby 101 docker image during upload script, for compatibility tests. --- tools/interop_matrix/client_matrix.py | 139 ++++++++++++--------- tools/interop_matrix/create_matrix_images.py | 39 +++++- tools/interop_matrix/patches/README.md | 38 ++++++ .../patches/ruby_v1.0.1/git_repo.patch | 34 +++++ tools/interop_matrix/run_interop_matrix_tests.py | 6 +- tools/interop_matrix/testcases/ruby__v1.0.1 | 20 +++ 6 files changed, 207 insertions(+), 69 deletions(-) create mode 100644 tools/interop_matrix/patches/README.md create mode 100644 tools/interop_matrix/patches/ruby_v1.0.1/git_repo.patch create mode 100755 tools/interop_matrix/testcases/ruby__v1.0.1 diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index c9a4996029..7b02f51725 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -23,6 +23,18 @@ def get_github_repo(lang): # all other languages use the grpc.git repo. }.get(lang, 'git@github.com:grpc/grpc.git') +def get_release_tags(lang): + return map(lambda r: get_release_tag_name(r), LANG_RELEASE_MATRIX[lang]) + +def get_release_tag_name(release_info): + assert len(release_info.keys()) == 1 + return release_info.keys()[0] + +def should_build_docker_interop_image_from_release_tag(lang): + if lang in ['go', 'java', 'node']: + return False + return True + # Dictionary of runtimes per language LANG_RUNTIME_MATRIX = { 'cxx': ['cxx'], # This is actually debian8. @@ -39,81 +51,84 @@ LANG_RUNTIME_MATRIX = { # a release tag pointing to the latest build of the branch. LANG_RELEASE_MATRIX = { 'cxx': [ - 'v1.0.1', - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - 'v1.7.2', + {'v1.0.1': None}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + {'v1.7.2': None}, ], 'go': [ - 'v1.0.5', - 'v1.2.1', - 'v1.3.0', - 'v1.4.2', - 'v1.5.2', - 'v1.6.0', - 'v1.7.0', - 'v1.7.1', - 'v1.7.2', - 'v1.7.3', - 'v1.8.0', + {'v1.0.5': None}, + {'v1.2.1': None}, + {'v1.3.0': None}, + {'v1.4.2': None}, + {'v1.5.2': None}, + {'v1.6.0': None}, + {'v1.7.0': None}, + {'v1.7.1': None}, + {'v1.7.2': None}, + {'v1.7.3': None}, + {'v1.8.0': None}, ], 'java': [ - 'v1.0.3', - 'v1.1.2', - 'v1.2.0', - 'v1.3.1', - 'v1.4.0', - 'v1.5.0', - 'v1.6.1', - 'v1.7.0', - 'v1.8.0', + {'v1.0.3': None}, + {'v1.1.2': None}, + {'v1.2.0': None}, + {'v1.3.1': None}, + {'v1.4.0': None}, + {'v1.5.0': None}, + {'v1.6.1': None}, + {'v1.7.0': None}, + {'v1.8.0': None}, ], 'python': [ - 'v1.0.x', - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - 'v1.7.2', + {'v1.0.x': None}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + {'v1.7.2': None}, ], 'node': [ - 'v1.0.1', - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - #'v1.7.1', Failing tests. + {'v1.0.1': None}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + #{'v1.7.1': None}, Failing tests ], 'ruby': [ - # Ruby v1.0.x doesn't have the fix #8914, therefore not supported. - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - 'v1.7.2', + {'v1.0.1': {'patch': [ + 'tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile', + 'tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh', + ]}}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + {'v1.7.2': None}, ], 'php': [ - 'v1.0.1', - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - 'v1.7.2', + {'v1.0.1': None}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + {'v1.7.2': None}, ], 'csharp': [ - #'v1.0.1', - 'v1.1.4', - 'v1.2.5', - 'v1.3.9', - 'v1.4.2', - 'v1.6.6', - 'v1.7.2', + #{'v1.0.1': None}, + {'v1.1.4': None}, + {'v1.2.5': None}, + {'v1.3.9': None}, + {'v1.4.2': None}, + {'v1.6.6': None}, + {'v1.7.2': None}, ], } diff --git a/tools/interop_matrix/create_matrix_images.py b/tools/interop_matrix/create_matrix_images.py index 493a7d5364..a292368131 100755 --- a/tools/interop_matrix/create_matrix_images.py +++ b/tools/interop_matrix/create_matrix_images.py @@ -39,7 +39,7 @@ _IMAGE_BUILDER = 'tools/run_tests/dockerize/build_interop_image.sh' _LANGUAGES = client_matrix.LANG_RUNTIME_MATRIX.keys() # All gRPC release tags, flattened, deduped and sorted. _RELEASES = sorted(list(set( - i for l in client_matrix.LANG_RELEASE_MATRIX.values() for i in l))) + client_matrix.get_release_tag_name(info) for lang in client_matrix.LANG_RELEASE_MATRIX.values() for info in lang))) # Destination directory inside docker image to keep extra info from build time. _BUILD_INFO = '/var/local/build_info' @@ -141,8 +141,11 @@ def build_image_jobspec(runtime, env, gcr_tag, stack_base): 'TTY_FLAG': '-t' } build_env.update(env) + image_builder_path = _IMAGE_BUILDER + if client_matrix.should_build_docker_interop_image_from_release_tag(lang): + image_builder_path = os.path.join(stack_base, _IMAGE_BUILDER) build_job = jobset.JobSpec( - cmdline=[_IMAGE_BUILDER], + cmdline=[image_builder_path], environ=build_env, shortname='build_docker_%s' % runtime, timeout_seconds=30*60) @@ -157,10 +160,10 @@ def build_all_images_for_lang(lang): releases = ['master'] else: if args.release == 'all': - releases = client_matrix.LANG_RELEASE_MATRIX[lang] + releases = client_matrix.get_release_tags(lang) else: # Build a particular release. - if args.release not in ['master'] + client_matrix.LANG_RELEASE_MATRIX[lang]: + if args.release not in ['master'] + client_matrix.get_release_tags(lang): jobset.message('SKIPPED', '%s for %s is not defined' % (args.release, lang), do_newline=True) @@ -223,6 +226,33 @@ def cleanup(): docker_images_cleanup = [] atexit.register(cleanup) +def maybe_apply_patches_on_git_tag(stack_base, lang, release): + files_to_patch = [] + for release_info in client_matrix.LANG_RELEASE_MATRIX[lang]: + if client_matrix.get_release_tag_name(release_info) == release: + files_to_patch = release_info[release].get('patch') + break + if not files_to_patch: + return + patch_file_relative_path = 'patches/%s_%s/git_repo.patch' % (lang, release) + patch_file = os.path.abspath(os.path.join(os.path.dirname(__file__), + patch_file_relative_path)) + if not os.path.exists(patch_file): + jobset.message('FAILED', 'expected patch file |%s| to exist' % patch_file) + sys.exit(1) + subprocess.check_output( + ['git', 'apply', patch_file], cwd=stack_base, stderr=subprocess.STDOUT) + for repo_relative_path in files_to_patch: + subprocess.check_output( + ['git', 'add', repo_relative_path], + cwd=stack_base, + stderr=subprocess.STDOUT) + subprocess.check_output( + ['git', 'commit', '-m', ('Hack performed on top of %s git ' + 'tag in order to build and run the %s ' + 'interop tests on that tag.' % (lang, release))], + cwd=stack_base, stderr=subprocess.STDOUT) + def checkout_grpc_stack(lang, release): """Invokes 'git check' for the lang/release and returns directory created.""" assert args.git_checkout and args.git_checkout_root @@ -252,6 +282,7 @@ def checkout_grpc_stack(lang, release): assert not os.path.dirname(__file__).startswith(stack_base) output = subprocess.check_output( ['git', 'checkout', release], cwd=stack_base, stderr=subprocess.STDOUT) + maybe_apply_patches_on_git_tag(stack_base, lang, release) commit_log = subprocess.check_output(['git', 'log', '-1'], cwd=stack_base) jobset.message('SUCCESS', 'git checkout', '%s: %s' % (str(output), commit_log), diff --git a/tools/interop_matrix/patches/README.md b/tools/interop_matrix/patches/README.md new file mode 100644 index 0000000000..0c0893f6f2 --- /dev/null +++ b/tools/interop_matrix/patches/README.md @@ -0,0 +1,38 @@ +# Patches to grpc repo tags for the backwards compatibility interop tests + +This directory has patch files that can be applied to different tags +of the grpc git repo in order to run the interop tests for a specific +language based on that tag. + +For example, because the ruby interop tests do not run on the v1.0.1 tag out +of the box, but we still want to test compatibility of the 1.0.1 ruby release +with other versions, we can apply a patch to the v1.0.1 tag from this directory +that makes the necessary changes that are needed to run the ruby interop tests +from that tag. We can then use that patch to build the docker image for the +ruby v1.0.1 interop tests. + +## How to add a new patch to this directory + +Patch files in this directory are meant to be applied to a git tag +with a `git apply` command. + +1. Under the `patches` directory, create a new subdirectory +titled `_` for the git tag being modified. + +2. `git checkout ` + +3. Make necessary modifications to the git repo at that tag. + +4. + +``` +git diff > ~/git_repo.patch +git checkout +cp ~/git_repo.patch tools/interop_matrix/patches/_/ +``` + +5. Edit the `LANGUAGE_RELEASE_MATRIX` in `client_matrix.py` for your language/tag +and add a `'patch': [,....]` entry to it's `dictionary`. + +After doing this, the interop image creation script can apply that patch to the +tag with `git apply` before uploading to the test image repo. diff --git a/tools/interop_matrix/patches/ruby_v1.0.1/git_repo.patch b/tools/interop_matrix/patches/ruby_v1.0.1/git_repo.patch new file mode 100644 index 0000000000..0cd92d691d --- /dev/null +++ b/tools/interop_matrix/patches/ruby_v1.0.1/git_repo.patch @@ -0,0 +1,34 @@ +diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile +index 88b5130..7ae9f7d 100644 +--- a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile ++++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile +@@ -70,12 +70,12 @@ RUN apt-get update && apt-get install -y time && apt-get clean + RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 + RUN \curl -sSL https://get.rvm.io | bash -s stable + +-# Install Ruby 2.1 +-RUN /bin/bash -l -c "rvm install ruby-2.1" +-RUN /bin/bash -l -c "rvm use --default ruby-2.1" ++# Install Ruby 2.1.8 ++RUN /bin/bash -l -c "rvm install ruby-2.1.8" ++RUN /bin/bash -l -c "rvm use --default ruby-2.1.8" + RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" + RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" +-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc" ++RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1.8' >> ~/.bashrc" + RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc" + + # Prepare ccache +diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh +index 97b3860..cec046d 100755 +--- a/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh ++++ b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh +@@ -38,7 +38,7 @@ git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + cp -r /var/local/jenkins/service_account $HOME || true + + cd /var/local/git/grpc +-rvm --default use ruby-2.1 ++rvm --default use ruby-2.1.8 + + # build Ruby interop client and server + (cd src/ruby && gem update bundler && bundle && rake compile) diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py index 4265bc5355..1bc35d9e02 100755 --- a/tools/interop_matrix/run_interop_matrix_tests.py +++ b/tools/interop_matrix/run_interop_matrix_tests.py @@ -41,7 +41,7 @@ import upload_test_results _LANGUAGES = client_matrix.LANG_RUNTIME_MATRIX.keys() # All gRPC release tags, flattened, deduped and sorted. _RELEASES = sorted(list(set( - i for l in client_matrix.LANG_RELEASE_MATRIX.values() for i in l))) + client_matrix.get_release_tag_name(info) for lang in client_matrix.LANG_RELEASE_MATRIX.values() for info in lang))) _TEST_TIMEOUT = 30 argp = argparse.ArgumentParser(description='Run interop tests.') @@ -93,10 +93,10 @@ def find_all_images_for_lang(lang): """ # Find all defined releases. if args.release == 'all': - releases = ['master'] + client_matrix.LANG_RELEASE_MATRIX[lang] + releases = ['master'] + client_matrix.get_release_tags(lang) else: # Look for a particular release. - if args.release not in ['master'] + client_matrix.LANG_RELEASE_MATRIX[lang]: + if args.release not in ['master'] + client_matrix.get_release_tags(lang): jobset.message('SKIPPED', '%s for %s is not defined' % (args.release, lang), do_newline=True) diff --git a/tools/interop_matrix/testcases/ruby__v1.0.1 b/tools/interop_matrix/testcases/ruby__v1.0.1 new file mode 100755 index 0000000000..effbef1d18 --- /dev/null +++ b/tools/interop_matrix/testcases/ruby__v1.0.1 @@ -0,0 +1,20 @@ +#!/bin/bash +echo "Testing ${docker_image:=grpc_interop_ruby:6bd1f0eb-51a4-4ad8-861c-1cbd7a929f33}" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response" +docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server" -- cgit v1.2.3