diff options
author | Nicolas Noble <nicolasnoble@users.noreply.github.com> | 2015-10-02 17:28:12 -0700 |
---|---|---|
committer | Nicolas Noble <nicolasnoble@users.noreply.github.com> | 2015-10-02 17:28:12 -0700 |
commit | f8460df564385af2197ffccb4d4004fd96d0eddd (patch) | |
tree | cafd892c347f532b2719e670753f6997ec09a68a | |
parent | 8a50de7e65a9121eb676bc0802c798f1886b35c7 (diff) | |
parent | 210a0ea598d44d725518ee68a27ad185fb0c16b0 (diff) |
Merge pull request #3605 from jtattermusch/interop_improvements
Build and run per-language containers for interop tests
17 files changed, 1123 insertions, 247 deletions
diff --git a/tools/jenkins/build_docker_and_run_interop_tests.sh b/tools/jenkins/build_docker_and_run_interop_tests.sh deleted file mode 100755 index d2d56d947b..0000000000 --- a/tools/jenkins/build_docker_and_run_interop_tests.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# This script is invoked by run_interop_tests.py to accommodate -# "interop tests under docker" scenario. You should never need to call this -# script on your own. - -set -ex - -cd `dirname $0`/../.. -git_root=`pwd` -cd - - -mkdir -p /tmp/ccache - -# Use image name based on Dockerfile checksum -DOCKER_IMAGE_NAME=grpc_jenkins_slave${docker_suffix}_`sha1sum tools/jenkins/grpc_jenkins_slave/Dockerfile | cut -f1 -d\ ` - -# Make sure docker image has been built. Should be instantaneous if so. -docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave$docker_suffix - -# Create a local branch so the child Docker script won't complain -git branch -f jenkins-docker - -# Make sure the CID files are gone. -rm -f prepare.cid server.cid client.cid - -# Prepare image for interop tests -docker run \ - -e CCACHE_DIR=/tmp/ccache \ - -i $TTY_FLAG \ - -v "$git_root:/var/local/jenkins/grpc" \ - -v /tmp/ccache:/tmp/ccache \ - --cidfile=prepare.cid \ - $DOCKER_IMAGE_NAME \ - bash -l /var/local/jenkins/grpc/tools/jenkins/docker_prepare_interop_tests.sh || DOCKER_FAILED="true" - -PREPARE_CID=`cat prepare.cid` - -# Create image from the container, we will spawn one docker for clients -# and one for servers. -INTEROP_IMAGE=interop_`uuidgen` -docker commit $PREPARE_CID $INTEROP_IMAGE -# remove container, possibly killing it first -docker rm -f $PREPARE_CID || true -echo "Successfully built image $INTEROP_IMAGE" - -# run interop servers under docker in the background -docker run \ - -d -i \ - $SERVERS_DOCKER_EXTRA_ARGS \ - --cidfile=server.cid \ - $INTEROP_IMAGE bash -l /var/local/git/grpc/tools/jenkins/docker_run_interop_servers.sh - -SERVER_CID=`cat server.cid` - -SERVER_PORTS="" -for tuple in $SERVER_PORT_TUPLES -do - # lookup under which port docker exposes given internal port - exposed_port=`docker port $SERVER_CID ${tuple#*:} | awk -F ":" '{print $NF}'` - - # override the port for corresponding cloud_to_cloud server - SERVER_PORTS+=" --override_server ${tuple%:*}=localhost:$exposed_port" - echo "${tuple%:*} server is exposed under port $exposed_port" -done - -# run interop clients -docker run \ - -e "RUN_TESTS_COMMAND=$RUN_TESTS_COMMAND $SERVER_PORTS" \ - -w /var/local/git/grpc \ - -i $TTY_FLAG \ - --net=host \ - --cidfile=client.cid \ - $INTEROP_IMAGE bash -l /var/local/git/grpc/tools/jenkins/docker_run_interop_tests.sh || DOCKER_FAILED="true" - -CLIENT_CID=`cat client.cid` - -echo "killing and removing server container $SERVER_CID" -docker rm -f $SERVER_CID || true - -docker cp $CLIENT_CID:/var/local/git/grpc/report.xml $git_root -docker rm -f $CLIENT_CID || true -docker rmi -f $DOCKER_IMAGE_NAME || true diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh new file mode 100755 index 0000000000..b5958588f2 --- /dev/null +++ b/tools/jenkins/build_interop_image.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This script is invoked by run_interop_tests.py to build the docker image +# for interop testing. You should never need to call this script on your own. + +set -x + +cd `dirname $0`/../.. +GRPC_ROOT=`pwd` +MOUNT_ARGS="-v $GRPC_ROOT:/var/local/jenkins/grpc" + +GRPC_JAVA_ROOT=`cd ../grpc-java && pwd` +if [ "$GRPC_JAVA_ROOT" != "" ] +then + MOUNT_ARGS+=" -v $GRPC_JAVA_ROOT:/var/local/jenkins/grpc-java" +else + echo "WARNING: grpc-java not found, it won't be mounted to the docker container." +fi + +GRPC_GO_ROOT=`cd ../grpc-go && pwd` +if [ "$GRPC_GO_ROOT" != "" ] +then + MOUNT_ARGS+=" -v $GRPC_GO_ROOT:/var/local/jenkins/grpc-go" +else + echo "WARNING: grpc-go not found, it won't be mounted to the docker container." +fi + +mkdir -p /tmp/ccache + +# Params: +# INTEROP_IMAGE - name of tag of the final interop image +# BASE_NAME - base name used to locate the base Dockerfile and build script +# TTY_FLAG - optional -t flag to make docker allocate tty. + +# Use image name based on Dockerfile checksum +BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/jenkins/$BASE_NAME/Dockerfile | cut -f1 -d\ ` + +# Make sure base docker image has been built. Should be instantaneous if so. +docker build -t $BASE_IMAGE --force-rm=true tools/jenkins/$BASE_NAME || exit $? + +# Create a local branch so the child Docker script won't complain +git branch -f jenkins-docker + +CIDFILE=`mktemp -u --suffix=.cid` + +# Prepare image for interop tests, commit it on success. +(docker run \ + -e CCACHE_DIR=/tmp/ccache \ + -i $TTY_FLAG \ + $MOUNT_ARGS \ + -v /tmp/ccache:/tmp/ccache \ + --cidfile=$CIDFILE \ + $BASE_IMAGE \ + bash -l /var/local/jenkins/grpc/tools/jenkins/$BASE_NAME/build_interop.sh \ + && docker commit `cat $CIDFILE` $INTEROP_IMAGE \ + && echo "Successfully built image $INTEROP_IMAGE") +EXITCODE=$? + +# remove intermediate container, possibly killing it first +docker rm -f `cat $CIDFILE` + +# remove the cidfile +rm -rf `cat $CIDFILE` + +exit $EXITCODE diff --git a/tools/jenkins/grpc_interop_csharp/Dockerfile b/tools/jenkins/grpc_interop_csharp/Dockerfile new file mode 100644 index 0000000000..3789cd3203 --- /dev/null +++ b/tools/jenkins/grpc_interop_csharp/Dockerfile @@ -0,0 +1,92 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# A work-in-progress Dockerfile that allows running gRPC test suites +# inside a docker container. + +FROM debian:jessie + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + ccache \ + curl \ + gcc \ + gcc-multilib \ + git \ + gyp \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + python-yaml \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + +################# +# C# dependencies + +# Update to a newer version of mono +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF +RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list +RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list +RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list +RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list + +# Install dependencies +RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \ + mono-devel \ + nunit \ + nunit-console \ + monodevelop + +# Download NuGet +RUN cd /var/local && wget www.nuget.org/NuGet.exe +ENV NUGET mono /var/local/NuGet.exe + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/grpc_interop_csharp/build_interop.sh b/tools/jenkins/grpc_interop_csharp/build_interop.sh new file mode 100755 index 0000000000..e91cbed81e --- /dev/null +++ b/tools/jenkins/grpc_interop_csharp/build_interop.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Builds C# interop server and client in a base image. +set -e + +mkdir -p /var/local/git +git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + +cd /var/local/git/grpc + +make install-certs + +# build C# interop client & server +make install_grpc_csharp_ext +(cd src/csharp && mono /var/local/NuGet.exe restore Grpc.sln) +(cd src/csharp && xbuild Grpc.sln) diff --git a/tools/jenkins/grpc_interop_cxx/Dockerfile b/tools/jenkins/grpc_interop_cxx/Dockerfile new file mode 100644 index 0000000000..1fa1907533 --- /dev/null +++ b/tools/jenkins/grpc_interop_cxx/Dockerfile @@ -0,0 +1,75 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# A work-in-progress Dockerfile that allows running gRPC test suites +# inside a docker container. + +FROM debian:jessie + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + ccache \ + curl \ + gcc \ + gcc-multilib \ + git \ + gyp \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + python-yaml \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + +################## +# C++ dependencies +RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/grpc_interop_cxx/build_interop.sh b/tools/jenkins/grpc_interop_cxx/build_interop.sh new file mode 100755 index 0000000000..4163e11ecc --- /dev/null +++ b/tools/jenkins/grpc_interop_cxx/build_interop.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Builds C++ interop server and client in a base image. +set -e + +mkdir -p /var/local/git +git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + +cd /var/local/git/grpc + +make install-certs + +# build C++ interop client & server +make interop_client interop_server diff --git a/tools/jenkins/grpc_interop_java/Dockerfile b/tools/jenkins/grpc_interop_java/Dockerfile new file mode 100644 index 0000000000..1ec24a95e3 --- /dev/null +++ b/tools/jenkins/grpc_interop_java/Dockerfile @@ -0,0 +1,58 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FROM debian:jessie + +# Install JDK 8 and Git +# +# TODO(temiola): simplify this if/when a simpler process is available. +# +RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \ + echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \ + echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \ + apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && \ + apt-get update && \ + apt-get -y install \ + git \ + libapr1 \ + oracle-java8-installer \ + && \ + apt-get clean && rm -r /var/cache/oracle-jdk8-installer/ + +ENV JAVA_HOME /usr/lib/jvm/java-8-oracle +ENV PATH $PATH:$JAVA_HOME/bin + +# Trigger download of as many Gradle artifacts as possible. +RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \ + cd grpc-java && \ + ./gradlew build -PskipCodegen=true && \ + rm -r "$(pwd)" + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/docker_run_interop_tests.sh b/tools/jenkins/grpc_interop_java/build_interop.sh index 29970afb25..4ee2f44e3d 100755 --- a/tools/jenkins/docker_run_interop_tests.sh +++ b/tools/jenkins/grpc_interop_java/build_interop.sh @@ -28,12 +28,12 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# This script is invoked by build_docker_and_run_interop_tests.sh inside -# a docker container. You should never need to call this script on your own. +# Builds Java interop server and client in a base image. set -e -nvm use 0.12 -rvm use ruby-2.1 +mkdir -p /var/local/git +git clone --recursive --depth 1 /var/local/jenkins/grpc-java /var/local/git/grpc-java -# run the cloud-to-prod interop tests -$RUN_TESTS_COMMAND +cd /var/local/git/grpc-java + +./gradlew :grpc-interop-testing:installDist -PskipCodegen=true diff --git a/tools/jenkins/grpc_interop_node/Dockerfile b/tools/jenkins/grpc_interop_node/Dockerfile new file mode 100644 index 0000000000..587227b942 --- /dev/null +++ b/tools/jenkins/grpc_interop_node/Dockerfile @@ -0,0 +1,79 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# A work-in-progress Dockerfile that allows running gRPC test suites +# inside a docker container. + +FROM debian:jessie + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + ccache \ + curl \ + gcc \ + gcc-multilib \ + git \ + gyp \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + python-yaml \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + +################## +# Node dependencies + +# Install nvm +RUN touch .profile +RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash +RUN /bin/bash -l -c "nvm install 0.12" + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/docker_run_interop_servers.sh b/tools/jenkins/grpc_interop_node/build_interop.sh index 9f29a65aaa..55e2a4081b 100755 --- a/tools/jenkins/docker_run_interop_servers.sh +++ b/tools/jenkins/grpc_interop_node/build_interop.sh @@ -28,23 +28,19 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# This script is invoked by run_jekins.sh. It contains the test logic -# that should run inside a docker container. +# Builds Node interop server and client in a base image. set -e +mkdir -p /var/local/git +git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + cd /var/local/git/grpc nvm use 0.12 -rvm use ruby-2.1 - -# If port env variable is set, run corresponding interop server on given port in background. -# TODO(jtattermusch): ideally, run_interop_tests.py would generate the commands to run servers. - -[ -z "${SERVER_PORT_cxx}" ] || bins/opt/interop_server --enable_ssl --port=${SERVER_PORT_cxx} & - -[ -z "${SERVER_PORT_node}" ] || node src/node/interop/interop_server.js --use_tls=true --port=${SERVER_PORT_node} & - -[ -z "${SERVER_PORT_ruby}" ] || ruby src/ruby/bin/interop/interop_server.rb --use_tls --port=${SERVER_PORT_ruby} & +nvm alias default 0.12 # prevent the need to run 'nvm use' in every shell -[ -z "${SERVER_PORT_csharp}" ] || (cd src/csharp/Grpc.IntegrationTesting.Server/bin/Debug && mono Grpc.IntegrationTesting.Server.exe --use_tls --port=${SERVER_PORT_csharp}) & +make install-certs -sleep infinity +# build Node interop client & server +npm install -g node-gyp +make install_c -C /var/local/git/grpc +(cd src/node && npm install && node-gyp rebuild) diff --git a/tools/jenkins/grpc_interop_php/Dockerfile b/tools/jenkins/grpc_interop_php/Dockerfile new file mode 100644 index 0000000000..0edc3c174d --- /dev/null +++ b/tools/jenkins/grpc_interop_php/Dockerfile @@ -0,0 +1,112 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# A work-in-progress Dockerfile that allows running gRPC test suites +# inside a docker container. + +FROM debian:jessie + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + ccache \ + curl \ + gcc \ + gcc-multilib \ + git \ + gyp \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + python-yaml \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + +################## +# Ruby dependencies + +# Install rvm +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" +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 "gem install bundler --no-ri --no-rdoc" + +################## +# PHP dependencies + +# Install dependencies + +RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \ + >> /etc/apt/sources.list.d/dotdeb.list" +RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \ + >> /etc/apt/sources.list.d/dotdeb.list" +RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add - + +RUN apt-get update && apt-get install -y \ + git php5 php5-dev phpunit unzip + +# ronn: a ruby tool used to convert markdown to man pages, used during the +# install of Protobuf extensions +# +# rake: a ruby version of make used to build the PHP Protobuf extension +RUN /bin/bash -l -c "rvm all do gem install ronn rake" + +ENV DEBIAN_FRONTEND noniteractive + +# Install composer +RUN curl -sS https://getcomposer.org/installer | php +RUN mv composer.phar /usr/local/bin/composer + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/docker_prepare_interop_tests.sh b/tools/jenkins/grpc_interop_php/build_interop.sh index a1fe0b72d2..745dea845d 100755 --- a/tools/jenkins/docker_prepare_interop_tests.sh +++ b/tools/jenkins/grpc_interop_php/build_interop.sh @@ -28,52 +28,32 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# This script is invoked by run_jekins.sh. It contains the test logic -# that should run inside a docker container. +# Builds PHP interop server and client in a base image. set -e mkdir -p /var/local/git git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc cd /var/local/git/grpc -nvm use 0.12 -rvm use ruby-2.1 +rvm --default use ruby-2.1 -# TODO(jtattermusch): use cleaner way to install root certs -mkdir -p /usr/local/share/grpc -cp etc/roots.pem /usr/local/share/grpc/ +make install-certs -# build C++ interop client & server -make interop_client interop_server +# gRPC core and protobuf need to be installed +make install -# build C# interop client & server -make install_grpc_csharp_ext -(cd src/csharp && mono /var/local/NuGet.exe restore Grpc.sln) -(cd src/csharp && xbuild Grpc.sln) - -# build Node interop client & server -npm install -g node-gyp -make install_c -C /var/local/git/grpc -(cd src/node && npm install && node-gyp rebuild) - -# build Ruby interop client and server -(cd src/ruby && gem update bundler && bundle && rake compile:grpc) - -# TODO(jtattermusch): add python - -# build PHP interop client -# TODO(jtattermusch): prerequisites for PHP should be installed sooner than here. -# Install composer -curl -sS https://getcomposer.org/installer | php -mv composer.phar /usr/local/bin/composer # Download the patched PHP protobuf so that PHP gRPC clients can be generated # from proto3 schemas. git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php + (cd src/php/ext/grpc && phpize && ./configure && make) -rvm all do gem install ronn rake + (cd third_party/protobuf && make install) + (cd /var/local/git/protobuf-php \ && rvm all do rake pear:package version=1.0 \ && pear install Protobuf-1.0.tgz) + (cd src/php && composer install) + (cd src/php && protoc-gen-php -i tests/interop/ -o tests/interop/ tests/interop/test.proto) diff --git a/tools/jenkins/grpc_interop_ruby/Dockerfile b/tools/jenkins/grpc_interop_ruby/Dockerfile new file mode 100644 index 0000000000..ff201fa291 --- /dev/null +++ b/tools/jenkins/grpc_interop_ruby/Dockerfile @@ -0,0 +1,87 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# A work-in-progress Dockerfile that allows running gRPC test suites +# inside a docker container. + +FROM debian:jessie + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + ccache \ + curl \ + gcc \ + gcc-multilib \ + git \ + gyp \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + python-yaml \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + + +################## +# Ruby dependencies + +# Install rvm +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" +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 "gem install bundler --no-ri --no-rdoc" + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/grpc_interop_ruby/build_interop.sh b/tools/jenkins/grpc_interop_ruby/build_interop.sh new file mode 100755 index 0000000000..7d407e7d0a --- /dev/null +++ b/tools/jenkins/grpc_interop_ruby/build_interop.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Builds Ruby interop server and client in a base image. +set -e + +mkdir -p /var/local/git +git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc + +cd /var/local/git/grpc +rvm --default use ruby-2.1 + +make install-certs + +# build Ruby interop client and server +(cd src/ruby && gem update bundler && bundle && rake compile:grpc) diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py new file mode 100755 index 0000000000..11686d46b0 --- /dev/null +++ b/tools/run_tests/dockerjob.py @@ -0,0 +1,115 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Helpers to run docker instances as jobs.""" + +import jobset +import tempfile +import time +import uuid +import os +import subprocess + +_DEVNULL = open(os.devnull, 'w') + +def wait_for_file(filepath, timeout_seconds=15): + """Wait until given file exists and returns its content.""" + started = time.time() + while time.time() - started < timeout_seconds: + if os.path.isfile(filepath): + with open(filepath, 'r') as f: + content = f.read() + # make sure we don't return empty content + if content: + return content + time.sleep(1) + raise Exception('Failed to read file %s.' % filepath) + + +def docker_mapped_port(cid, port): + """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]) + + +def finish_jobs(jobs): + """Kills given docker containers and waits for corresponding jobs to finish""" + for job in jobs: + job.kill(suppress_failure=True) + + while any(job.is_running() for job in jobs): + time.sleep(1) + + +def image_exists(image): + """Returns True if given docker image exists.""" + return subprocess.call(['docker','inspect', image], + stdout=_DEVNULL, + stderr=_DEVNULL) == 0 + + +def remove_image(image, skip_nonexistent=False, max_retries=10): + """Attempts to remove docker image with retries.""" + 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: + return True + time.sleep(2) + print 'Failed to remove docker image %s' % image + return False + + +class DockerJob: + """Encapsulates a job""" + + def __init__(self, spec): + self._spec = spec + self._job = jobset.Job(spec, bin_hash=None, newline_on_success=True, travis=True, add_env={}, xml_report=None) + self._cidfile = spec.cidfile + self._cid = None + + def cid(self): + """Gets cid of this container""" + if not self._cid: + self._cid = wait_for_file(self._cidfile) + return self._cid + + def mapped_port(self, port): + return docker_mapped_port(self.cid(), port) + + def kill(self, suppress_failure=False): + """Sends kill signal to the container.""" + if suppress_failure: + self._job.suppress_failure_message() + return subprocess.call(['docker','kill', self.cid()]) == 0 + + def is_running(self): + """Polls a job and returns True if given job is still running.""" + return self._job.state(jobset.NoCache()) == jobset._RUNNING diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py index b9ec020f9e..87be703b4c 100755 --- a/tools/run_tests/jobset.py +++ b/tools/run_tests/jobset.py @@ -180,6 +180,7 @@ class Job(object): name=self._spec.shortname) if xml_report is not None else None self._retries = 0 self._timeout_retries = 0 + self._suppress_failure_message = False message('START', spec.shortname, do_newline=self._travis) self.start() @@ -220,9 +221,10 @@ class Job(object): self.start() else: self._state = _FAILURE - message('FAILED', '%s [ret=%d, pid=%d]' % ( - self._spec.shortname, self._process.returncode, self._process.pid), - stdout, do_newline=True) + if not self._suppress_failure_message: + message('FAILED', '%s [ret=%d, pid=%d]' % ( + self._spec.shortname, self._process.returncode, self._process.pid), + stdout, do_newline=True) if self._xml_test is not None: ET.SubElement(self._xml_test, 'failure', message='Failure').text else: @@ -254,6 +256,9 @@ class Job(object): self._state = _KILLED self._process.terminate() + def suppress_failure_message(self): + self._suppress_failure_message = True + class Jobset(object): """Manages one run of jobs.""" diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 6445513fbe..46b34fea4c 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -31,14 +31,22 @@ """Run interop (cross-language) tests in parallel.""" import argparse +import dockerjob import itertools import xml.etree.cElementTree as ET import jobset +import multiprocessing import os import subprocess import sys +import tempfile import time +import uuid +ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..')) +os.chdir(ROOT) + +_DEFAULT_SERVER_PORT=8080 _CLOUD_TO_PROD_BASE_ARGS = [ '--server_host_override=grpc-test.sandbox.google.com', @@ -54,12 +62,15 @@ _CLOUD_TO_CLOUD_BASE_ARGS = [ _SSL_CERT_ENV = { 'SSL_CERT_FILE':'/usr/local/share/grpc/roots.pem' } # TODO(jtatttermusch) unify usage of --use_tls and --use_tls=true +# TODO(jtatttermusch) unify usage of --use_prod_roots and --use_test_ca + class CXXLanguage: def __init__(self): self.client_cmdline_base = ['bins/opt/interop_client'] self.client_cwd = None + self.server_cwd = None def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -72,6 +83,9 @@ class CXXLanguage: def cloud_to_prod_env(self): return None + def server_args(self): + return ['bins/opt/interop_server', '--use_tls=true'] + def __str__(self): return 'c++' @@ -81,6 +95,7 @@ class CSharpLanguage: def __init__(self): 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' def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -93,15 +108,44 @@ class CSharpLanguage: def cloud_to_prod_env(self): return _SSL_CERT_ENV + def server_args(self): + return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls'] + def __str__(self): return 'csharp' +class JavaLanguage: + + def __init__(self): + self.client_cmdline_base = ['./run-test-client.sh'] + self.client_cwd = '../grpc-java' + self.server_cwd = '../grpc-java' + + def cloud_to_prod_args(self): + return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + + ['--use_tls=true']) + + def cloud_to_cloud_args(self): + return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS + + ['--use_tls=true', '--use_test_ca=true']) + + def cloud_to_prod_env(self): + return None + + def server_args(self): + return ['./run-test-server.sh', '--use_tls=true'] + + def __str__(self): + return 'java' + + class NodeLanguage: def __init__(self): self.client_cmdline_base = ['node', 'src/node/interop/interop_client.js'] self.client_cwd = None + self.server_cwd = None def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -114,6 +158,9 @@ class NodeLanguage: def cloud_to_prod_env(self): return _SSL_CERT_ENV + def server_args(self): + return ['node', 'src/node/interop/interop_server.js', '--use_tls=true'] + def __str__(self): return 'node' @@ -144,6 +191,7 @@ class RubyLanguage: def __init__(self): self.client_cmdline_base = ['ruby', 'src/ruby/bin/interop/interop_client.rb'] self.client_cwd = None + self.server_cwd = None def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + @@ -156,64 +204,151 @@ class RubyLanguage: def cloud_to_prod_env(self): return _SSL_CERT_ENV + def server_args(self): + return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls'] + def __str__(self): return 'ruby' -# TODO(jtattermusch): add php and python once we get them working +# TODO(jtattermusch): python once we get it working _LANGUAGES = { 'c++' : CXXLanguage(), 'csharp' : CSharpLanguage(), + 'java' : JavaLanguage(), 'node' : NodeLanguage(), 'php' : PHPLanguage(), 'ruby' : RubyLanguage(), } -# languages supported as cloud_to_cloud servers +# languages supported as cloud_to_cloud servers # TODO(jtattermusch): enable other languages as servers as well -_SERVERS = { 'c++' : 8010, 'node' : 8040, 'csharp': 8070 } +_SERVERS = ['c++', 'node', 'csharp', 'java'] -# TODO(jtattermusch): add empty_stream once C++ start supporting it. +# 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', - 'cancel_after_begin', 'cancel_after_first_response', - 'timeout_on_sleeping_server'] + 'cancel_after_begin', 'cancel_after_first_response'] -def cloud_to_prod_jobspec(language, test_case): +def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None): + """Wraps given cmdline array to create 'docker run' cmdline from it.""" + docker_cmdline = ['docker', 'run', '-i', '--rm=true'] + + # turn environ into -e docker args + if environ: + for k,v in environ.iteritems(): + docker_cmdline += ['-e', '%s=%s' % (k,v)] + + # set working directory + workdir = '/var/local/git/grpc' + if cwd: + workdir = os.path.join(workdir, cwd) + docker_cmdline += ['-w', workdir] + + docker_cmdline += docker_args + [image] + cmdline + return docker_cmdline + + +def bash_login_cmdline(cmdline): + """Creates bash -l -c cmdline from args list.""" + # Use login shell: + # * rvm and nvm require it + # * makes error messages clearer if executables are missing + return ['bash', '-l', '-c', ' '.join(cmdline)] + + +def cloud_to_prod_jobspec(language, test_case, docker_image=None): """Creates jobspec for cloud-to-prod interop test""" - cmdline = language.cloud_to_prod_args() + ['--test_case=%s' % test_case] + cmdline = bash_login_cmdline(language.cloud_to_prod_args() + + ['--test_case=%s' % test_case]) + cwd = language.client_cwd + environ = language.cloud_to_prod_env() + if docker_image: + cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, environ=environ) + cwd = None + environ = None + test_job = jobset.JobSpec( cmdline=cmdline, - cwd=language.client_cwd, + cwd=cwd, + environ=environ, shortname="cloud_to_prod:%s:%s" % (language, test_case), - environ=language.cloud_to_prod_env(), - timeout_seconds=60) + timeout_seconds=2*60, + flake_retries=5 if args.allow_flakes else 0, + timeout_retries=2 if args.allow_flakes else 0) return test_job def cloud_to_cloud_jobspec(language, test_case, server_name, server_host, - server_port): + server_port, docker_image=None): """Creates jobspec for cloud-to-cloud interop test""" - cmdline = language.cloud_to_cloud_args() + ['--test_case=%s' % test_case, - '--server_host=%s' % server_host, - '--server_port=%s' % server_port ] + cmdline = bash_login_cmdline(language.cloud_to_cloud_args() + + ['--test_case=%s' % test_case, + '--server_host=%s' % server_host, + '--server_port=%s' % server_port ]) + cwd = language.client_cwd + if docker_image: + cmdline = docker_run_cmdline(cmdline, + image=docker_image, + cwd=cwd, + docker_args=['--net=host']) + cwd = None test_job = jobset.JobSpec( cmdline=cmdline, - cwd=language.client_cwd, + cwd=cwd, shortname="cloud_to_cloud:%s:%s_server:%s" % (language, server_name, test_case), - timeout_seconds=60) + timeout_seconds=2*60, + flake_retries=5 if args.allow_flakes else 0, + timeout_retries=2 if args.allow_flakes else 0) return test_job + +def server_jobspec(language, docker_image): + """Create jobspec for running a server""" + cidfile = tempfile.mktemp() + cmdline = bash_login_cmdline(language.server_args() + + ['--port=%s' % _DEFAULT_SERVER_PORT]) + docker_cmdline = docker_run_cmdline(cmdline, + image=docker_image, + cwd=language.server_cwd, + docker_args=['-p', str(_DEFAULT_SERVER_PORT), + '--cidfile', cidfile]) + server_job = jobset.JobSpec( + cmdline=docker_cmdline, + shortname="interop_server:%s" % language, + timeout_seconds=30*60) + server_job.cidfile = cidfile + return server_job + + +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} + if not args.travis: + env['TTY_FLAG'] = '-t' + build_job = jobset.JobSpec( + cmdline=['tools/jenkins/build_interop_image.sh'], + environ=env, + shortname="build_docker_%s" % (language), + timeout_seconds=30*60) + build_job.tag = tag + return build_job + + argp = argparse.ArgumentParser(description='Run interop tests.') argp.add_argument('-l', '--language', choices=['all'] + sorted(_LANGUAGES), nargs='+', default=['all'], help='Clients to run.') -argp.add_argument('-j', '--jobs', default=24, type=int) +argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int) argp.add_argument('--cloud_to_prod', default=False, action='store_const', @@ -242,9 +377,14 @@ argp.add_argument('--use_docker', help='Run all the interop tests under docker. That provides ' + 'additional isolation and prevents the need to install ' + 'language specific prerequisites. Only available on Linux.') +argp.add_argument('--allow_flakes', + default=False, + action='store_const', + const=True, + help="Allow flaky tests to show as passing (re-runs failed tests up to five times)") args = argp.parse_args() -servers = set(s for s in itertools.chain.from_iterable(_SERVERS.iterkeys() +servers = set(s for s in itertools.chain.from_iterable(_SERVERS if x == 'all' else [x] for x in args.server)) @@ -257,73 +397,99 @@ if args.use_docker: print 'copied to the docker environment.' time.sleep(5) - child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ] - run_tests_cmd = ('tools/run_tests/run_interop_tests.py %s' % - " ".join(child_argv[1:])) - - # cmdline args to pass to the container running servers. - servers_extra_docker_args = '' - server_port_tuples = '' - for server in servers: - port = _SERVERS[server] - servers_extra_docker_args += ' -p %s' % port - servers_extra_docker_args += ' -e SERVER_PORT_%s=%s' % (server.replace("+", "x"), port) - server_port_tuples += ' %s:%s' % (server, port) - - env = os.environ.copy() - env['RUN_TESTS_COMMAND'] = run_tests_cmd - env['SERVERS_DOCKER_EXTRA_ARGS'] = servers_extra_docker_args - env['SERVER_PORT_TUPLES'] = server_port_tuples - if not args.travis: - env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins. - - subprocess.check_call(['tools/jenkins/build_docker_and_run_interop_tests.sh'], - shell=True, - env=env) - sys.exit(0) +if not args.use_docker and servers: + print "Running interop servers is only supported with --use_docker option enabled." + sys.exit(1) languages = set(_LANGUAGES[l] for l in itertools.chain.from_iterable( _LANGUAGES.iterkeys() if x == 'all' else [x] for x in args.language)) -jobs = [] -if args.cloud_to_prod: - for language in languages: - for test_case in _TEST_CASES: - test_job = cloud_to_prod_jobspec(language, test_case) - jobs.append(test_job) - -# default servers to "localhost" and the default port -server_addresses = dict((s, ("localhost", _SERVERS[s])) for s in servers) - -for server in args.override_server: - server_name = server[0] - (server_host, server_port) = server[1].split(":") - server_addresses[server_name] = (server_host, server_port) - -for server_name, server_address in server_addresses.iteritems(): - (server_host, server_port) = server_address - for language in languages: - for test_case in _TEST_CASES: - test_job = cloud_to_cloud_jobspec(language, - test_case, - server_name, - server_host, - server_port) - jobs.append(test_job) - -if not jobs: - print "No jobs to run." - sys.exit(1) - -root = ET.Element('testsuites') -testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') - -if jobset.run(jobs, newline_on_success=True, maxjobs=args.jobs, xml_report=testsuite): - jobset.message('SUCCESS', 'All tests passed', do_newline=True) -else: - jobset.message('FAILED', 'Some tests failed', do_newline=True) - -tree = ET.ElementTree(root) -tree.write('report.xml', encoding='UTF-8') +docker_images={} +if args.use_docker: + # languages for which to build docker images + languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] + + [s for s in servers])) + + build_jobs = [] + for l in languages_to_build: + job = build_interop_image_jobspec(l) + docker_images[str(l)] = job.tag + build_jobs.append(job) + + if build_jobs: + jobset.message('START', 'Building interop docker images.', do_newline=True) + if jobset.run(build_jobs, newline_on_success=True, maxjobs=args.jobs): + jobset.message('SUCCESS', 'All docker images built successfully.', do_newline=True) + else: + jobset.message('FAILED', 'Failed to build interop docker images.', do_newline=True) + for image in docker_images.itervalues(): + dockerjob.remove_image(image, skip_nonexistent=True) + exit(1); + +# Start interop servers. +server_jobs={} +server_addresses={} +try: + for s in servers: + lang = str(s) + spec = server_jobspec(_LANGUAGES[lang], docker_images.get(lang)) + job = dockerjob.DockerJob(spec) + server_jobs[lang] = job + server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT)) + + + jobs = [] + if args.cloud_to_prod: + for language in languages: + for test_case in _TEST_CASES: + test_job = cloud_to_prod_jobspec(language, test_case, + docker_image=docker_images.get(str(language))) + jobs.append(test_job) + + for server in args.override_server: + server_name = server[0] + (server_host, server_port) = server[1].split(':') + server_addresses[server_name] = (server_host, server_port) + + for server_name, server_address in server_addresses.iteritems(): + (server_host, server_port) = server_address + for language in languages: + for test_case in _TEST_CASES: + test_job = cloud_to_cloud_jobspec(language, + test_case, + server_name, + server_host, + server_port, + docker_image=docker_images.get(str(language))) + jobs.append(test_job) + + if not jobs: + print "No jobs to run." + for image in docker_images.itervalues(): + dockerjob.remove_image(image, skip_nonexistent=True) + sys.exit(1) + + root = ET.Element('testsuites') + testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') + + if jobset.run(jobs, newline_on_success=True, maxjobs=args.jobs, xml_report=testsuite): + jobset.message('SUCCESS', 'All tests passed', do_newline=True) + else: + jobset.message('FAILED', 'Some tests failed', do_newline=True) + + tree = ET.ElementTree(root) + tree.write('report.xml', encoding='UTF-8') + +finally: + # Check if servers are still running. + for server, job in server_jobs.iteritems(): + if not job.is_running(): + print 'Server "%s" has exited prematurely.' % server + + dockerjob.finish_jobs([j for j in server_jobs.itervalues()]) + + for image in docker_images.itervalues(): + print 'Removing docker image %s' % image + dockerjob.remove_image(image) |