1#!/bin/bash
2#
3# Build and runs tests for the protobuf project.  The tests as written here are
4# used by both Jenkins and Travis, though some specialized logic is required to
5# handle the differences between them.
6
7on_travis() {
8  if [ "$TRAVIS" == "true" ]; then
9    "$@"
10  fi
11}
12
13# For when some other test needs the C++ main build, including protoc and
14# libprotobuf.
15internal_build_cpp() {
16  if [ -f src/protoc ]; then
17    # Already built.
18    return
19  fi
20
21  if [[ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]]; then
22    # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more
23    # decent C++ 11 support in order to compile conformance tests.
24    sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
25    sudo apt-get update -qq
26    sudo apt-get install -qq g++-4.8
27    export CXX="g++-4.8" CC="gcc-4.8"
28  fi
29
30  ./autogen.sh
31  ./configure
32  make -j2
33}
34
35build_cpp() {
36  internal_build_cpp
37  make check -j2
38  cd conformance && make test_cpp && cd ..
39
40  # Verify benchmarking code can build successfully.
41  cd benchmarks && make && ./generate-datasets && cd ..
42}
43
44build_cpp_distcheck() {
45  ./autogen.sh
46  ./configure
47  make distcheck -j2
48}
49
50build_csharp() {
51  # Just for the conformance tests. We don't currently
52  # need to really build protoc, but it's simplest to keep with the
53  # conventions of the other builds.
54  internal_build_cpp
55  NUGET=/usr/local/bin/nuget.exe
56
57  if [ "$TRAVIS" == "true" ]; then
58    # Install latest version of Mono
59    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
60    echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
61    echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
62    sudo apt-get update -qq
63    sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit
64    wget www.nuget.org/NuGet.exe -O nuget.exe
65    NUGET=../../nuget.exe
66  fi
67
68  (cd csharp/src; mono $NUGET restore)
69  csharp/buildall.sh
70  cd conformance && make test_csharp && cd ..
71}
72
73build_golang() {
74  # Go build needs `protoc`.
75  internal_build_cpp
76  # Add protoc to the path so that the examples build finds it.
77  export PATH="`pwd`/src:$PATH"
78
79  # Install Go and the Go protobuf compiler plugin.
80  sudo apt-get update -qq
81  sudo apt-get install -qq golang
82  export GOPATH="$HOME/gocode"
83  mkdir -p "$GOPATH/src/github.com/google"
84  ln -s "`pwd`" "$GOPATH/src/github.com/google/protobuf"
85  export PATH="$GOPATH/bin:$PATH"
86  go get github.com/golang/protobuf/protoc-gen-go
87
88  cd examples && make gotest && cd ..
89}
90
91use_java() {
92  version=$1
93  case "$version" in
94    jdk6)
95      on_travis sudo apt-get install openjdk-6-jdk
96      export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH
97      ;;
98    jdk7)
99      on_travis sudo apt-get install openjdk-7-jdk
100      export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
101      ;;
102    oracle7)
103      if [ "$TRAVIS" == "true" ]; then
104        sudo apt-get install python-software-properties # for apt-add-repository
105        echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | \
106          sudo debconf-set-selections
107        yes | sudo apt-add-repository ppa:webupd8team/java
108        yes | sudo apt-get install oracle-java7-installer
109      fi;
110      export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH
111      ;;
112  esac
113
114  if [ "$TRAVIS" != "true" ]; then
115    MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository
116    MVN="$MVN -e -X --offline -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
117  fi;
118
119  which java
120  java -version
121}
122
123# --batch-mode supresses download progress output that spams the logs.
124MVN="mvn --batch-mode"
125
126build_java() {
127  version=$1
128  dir=java_$version
129  # Java build needs `protoc`.
130  internal_build_cpp
131  cp -r java $dir
132  cd $dir && $MVN clean && $MVN test
133  cd ../..
134}
135
136# The conformance tests are hard-coded to work with the $ROOT/java directory.
137# So this can't run in parallel with two different sets of tests.
138build_java_with_conformance_tests() {
139  # Java build needs `protoc`.
140  internal_build_cpp
141  cd java && $MVN test && $MVN install
142  cd util && $MVN package assembly:single
143  cd ../..
144  cd conformance && make test_java && cd ..
145}
146
147build_javanano() {
148  # Java build needs `protoc`.
149  internal_build_cpp
150  cd javanano && $MVN test && cd ..
151}
152
153build_java_jdk6() {
154  use_java jdk6
155  build_java jdk6
156}
157build_java_jdk7() {
158  use_java jdk7
159  build_java_with_conformance_tests
160}
161build_java_oracle7() {
162  use_java oracle7
163  build_java oracle7
164}
165
166build_javanano_jdk6() {
167  use_java jdk6
168  build_javanano
169}
170build_javanano_jdk7() {
171  use_java jdk7
172  build_javanano
173}
174build_javanano_oracle7() {
175  use_java oracle7
176  build_javanano
177}
178
179internal_install_python_deps() {
180  if [ "$TRAVIS" != "true" ]; then
181    return;
182  fi
183  # Install tox (OS X doesn't have pip).
184  if [ $(uname -s) == "Darwin" ]; then
185    sudo easy_install tox
186  else
187    sudo pip install tox
188  fi
189  # Only install Python2.6/3.x on Linux.
190  if [ $(uname -s) == "Linux" ]; then
191    sudo apt-get install -y python-software-properties # for apt-add-repository
192    sudo apt-add-repository -y ppa:fkrull/deadsnakes
193    sudo apt-get update -qq
194    sudo apt-get install -y python2.6 python2.6-dev
195    sudo apt-get install -y python3.3 python3.3-dev
196    sudo apt-get install -y python3.4 python3.4-dev
197  fi
198}
199
200internal_objectivec_common () {
201  # Make sure xctool is up to date. Adapted from
202  #  http://docs.travis-ci.com/user/osx-ci-environment/
203  # We don't use a before_install because we test multiple OSes.
204  brew update
205  brew outdated xctool || brew upgrade xctool
206  # Reused the build script that takes care of configuring and ensuring things
207  # are up to date. Xcode and conformance tests will be directly invoked.
208  objectivec/DevTools/full_mac_build.sh \
209      --core-only --skip-xcode --skip-objc-conformance
210}
211
212internal_xctool_debug_and_release() {
213  # Always use -reporter plain to avoid escape codes in output (makes travis
214  # logs easier to read).
215  xctool -reporter plain -configuration Debug "$@"
216  xctool -reporter plain -configuration Release "$@"
217}
218
219build_objectivec_ios() {
220  internal_objectivec_common
221  # https://github.com/facebook/xctool/issues/509 - unlike xcodebuild, xctool
222  # doesn't support >1 destination, so we have to build first and then run the
223  # tests one destination at a time.
224  internal_xctool_debug_and_release \
225    -project objectivec/ProtocolBuffers_iOS.xcodeproj \
226    -scheme ProtocolBuffers \
227    -sdk iphonesimulator \
228    build-tests
229  IOS_DESTINATIONS=(
230    "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
231    "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
232    "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
233    "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
234  )
235  for i in "${IOS_DESTINATIONS[@]}" ; do
236    internal_xctool_debug_and_release \
237      -project objectivec/ProtocolBuffers_iOS.xcodeproj \
238      -scheme ProtocolBuffers \
239      -sdk iphonesimulator \
240      -destination "${i}" \
241      run-tests
242  done
243}
244
245build_objectivec_osx() {
246  internal_objectivec_common
247  internal_xctool_debug_and_release \
248    -project objectivec/ProtocolBuffers_OSX.xcodeproj \
249    -scheme ProtocolBuffers \
250    -destination "platform=OS X,arch=x86_64" \
251    test
252  cd conformance && make test_objc && cd ..
253}
254
255build_python() {
256  internal_build_cpp
257  internal_install_python_deps
258  cd python
259  # Only test Python 2.6/3.x on Linux
260  if [ $(uname -s) == "Linux" ]; then
261    envlist=py\{26,27,33,34\}-python
262  else
263    envlist=py27-python
264  fi
265  tox -e $envlist
266  cd ..
267}
268
269build_python_cpp() {
270  internal_build_cpp
271  internal_install_python_deps
272  export LD_LIBRARY_PATH=../src/.libs # for Linux
273  export DYLD_LIBRARY_PATH=../src/.libs # for OS X
274  cd python
275  # Only test Python 2.6/3.x on Linux
276  if [ $(uname -s) == "Linux" ]; then
277    # py26 is currently disabled due to json_format
278    envlist=py\{27,33,34\}-cpp
279  else
280    envlist=py27-cpp
281  fi
282  tox -e $envlist
283  cd ..
284}
285
286build_ruby19() {
287  internal_build_cpp  # For conformance tests.
288  cd ruby && bash travis-test.sh ruby-1.9 && cd ..
289}
290build_ruby20() {
291  internal_build_cpp  # For conformance tests.
292  cd ruby && bash travis-test.sh ruby-2.0 && cd ..
293}
294build_ruby21() {
295  internal_build_cpp  # For conformance tests.
296  cd ruby && bash travis-test.sh ruby-2.1 && cd ..
297}
298build_ruby22() {
299  internal_build_cpp  # For conformance tests.
300  cd ruby && bash travis-test.sh ruby-2.2 && cd ..
301}
302build_jruby() {
303  internal_build_cpp  # For conformance tests.
304  cd ruby && bash travis-test.sh jruby && cd ..
305}
306
307build_javascript() {
308  internal_build_cpp
309  cd js && npm install && npm test && cd ..
310}
311
312# Note: travis currently does not support testing more than one language so the
313# .travis.yml cheats and claims to only be cpp.  If they add multiple language
314# support, this should probably get updated to install steps and/or
315# rvm/gemfile/jdk/etc. entries rather than manually doing the work.
316
317# .travis.yml uses matrix.exclude to block the cases where app-get can't be
318# use to install things.
319
320# -------- main --------
321
322if [ "$#" -ne 1 ]; then
323  echo "
324Usage: $0 { cpp |
325            csharp |
326            java_jdk6 |
327            java_jdk7 |
328            java_oracle7 |
329            javanano_jdk6 |
330            javanano_jdk7 |
331            javanano_oracle7 |
332            objectivec_ios |
333            objectivec_osx |
334            python |
335            python_cpp |
336            ruby19 |
337            ruby20 |
338            ruby21 |
339            ruby22 |
340            jruby }
341"
342  exit 1
343fi
344
345set -e  # exit immediately on error
346set -x  # display all commands
347eval "build_$1"
348