You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ab...@apache.org on 2017/11/30 18:53:25 UTC

[geode] branch develop updated: GEODE-4023: Add precheckin tests to pipeline.

This is an automated email from the ASF dual-hosted git repository.

abaker pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new d03b3f0  GEODE-4023: Add precheckin tests to pipeline.
d03b3f0 is described below

commit d03b3f06f347b87feaac8953c16786e5ea53ea55
Author: Sean Goller <sg...@pivotal.io>
AuthorDate: Tue Nov 28 13:36:40 2017 -0800

    GEODE-4023: Add precheckin tests to pipeline.
    
    * Add support for running DUnit tests in concourse.
    * Add scripts to run and archive test results.
    * Add concourse jobs for FlakyTest, IntegrationTest, DistributedTest and
      AcceptanceTest.
    * Clean up Dockerfile to optimize package installation
    * Ensure combineReports gets run so test results are archived regardless
      of how the job completes.
    [GEODE-4023]
---
 ci/docker/Dockerfile           |  32 ++++-
 ci/docker/docker.list          |  17 +++
 ci/docker/initdocker           |  31 +++++
 ci/docker/tini-wrapper.go      |  42 ++++++
 ci/pipelines/develop.yml       | 284 +++++++++++++++++++++++++++++++++++++++--
 ci/pipelines/docker-images.yml |   2 +-
 ci/scripts/build.sh            |   9 +-
 ci/scripts/test-archive.sh     | 121 ++++++++++++++++++
 ci/scripts/test-run.sh         | 142 +++++++++++++++++++++
 9 files changed, 662 insertions(+), 18 deletions(-)

diff --git a/ci/docker/Dockerfile b/ci/docker/Dockerfile
index 70e3b5b..097bba5 100644
--- a/ci/docker/Dockerfile
+++ b/ci/docker/Dockerfile
@@ -16,19 +16,37 @@
 FROM apachegeode/geode-build
 ENTRYPOINT []
 
-# Setup Google APT repository
-RUN apt-get update && \
-    apt-get install -y lsb-release && \
-    echo "deb http://packages.cloud.google.com/apt cloud-sdk-$(lsb_release -c -s) main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
-    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
-    apt-get update && apt-get install -y google-cloud-sdk && \
-    apt-get clean
+# apt prerequisites for installing docker and gcloud
+RUN apt-get update
+RUN apt-get install -y apt-transport-https ca-certificates aptitude lsb-release jq unzip vim htop golang cgroupfs-mount
+RUN apt-key adv --keyserver hkp://pgp.mit.edu --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
+RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
+
+# Setup APT repostories
+ADD docker.list /etc/apt/sources.list.d/
+RUN echo "deb http://packages.cloud.google.com/apt cloud-sdk-$(lsb_release -c -s) main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
+
+# Install docker and gcloud
+RUN apt-get update
+RUN apt-get purge lxc-docker
+RUN apt-get install -y docker-engine google-cloud-sdk && apt-get clean
 
 # For a CI tool, disable updates to gcloud since they'll be thrown away at end of run
 RUN gcloud config set core/disable_usage_reporting true && \
     gcloud config set component_manager/disable_update_check true && \
     gcloud config set metrics/environment github_docker_image
 
+# Install Tini and associated wrapper
+ADD https://github.com/krallin/tini/releases/download/v0.14.0/tini-static-amd64 /usr/local/bin/tini
+RUN chmod +x /usr/local/bin/tini
+ADD tini-wrapper.go .
+RUN go build -o /usr/local/bin/tini-wrapper ./tini-wrapper.go
+
+# Init script for docker inside our workers
+ADD ./initdocker /usr/local/bin/initdocker
+RUN chmod +x /usr/local/bin/initdocker
+
+# Cache gradle for performance
 ENV GRADLE_USER_HOME /usr/local/maven_files
 WORKDIR /tmp/work
 ADD cache_dependencies.sh cache_dependencies.sh
diff --git a/ci/docker/docker.list b/ci/docker/docker.list
new file mode 100644
index 0000000..e719b64
--- /dev/null
+++ b/ci/docker/docker.list
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+deb https://apt.dockerproject.org/repo debian-stretch main
diff --git a/ci/docker/initdocker b/ci/docker/initdocker
new file mode 100644
index 0000000..7340f95
--- /dev/null
+++ b/ci/docker/initdocker
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+IMAGE_ROOT="$PWD/image-root"
+
+/usr/bin/cgroupfs-mount
+
+mkdir -p /tmp/build/graph
+mount -t tmpfs -o size=5g tmpfs /tmp/build/graph
+
+dockerd --data-root /tmp/build/graph -s aufs >/tmp/dockerd.log 2>&1 &
+
+until docker info &>/dev/null; do
+  echo waiting for docker to come up...
+  sleep 1
+done
diff --git a/ci/docker/tini-wrapper.go b/ci/docker/tini-wrapper.go
new file mode 100644
index 0000000..15636a7
--- /dev/null
+++ b/ci/docker/tini-wrapper.go
@@ -0,0 +1,42 @@
+package main
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+import (
+	"os"
+	"syscall"
+	"os/exec"
+	"log"
+)
+
+func main() {
+	tini, err := exec.LookPath("tini")
+	if err != nil {
+		log.Panicf("Unable to find 'tini' in PATH")
+	}
+
+	os.Setenv("TINI_SUBREAPER", "1")
+
+	tiniArgs := []string{"-s", os.Args[1], "--"}
+	for _, v := range os.Args[2:] {
+		tiniArgs = append(tiniArgs, v)
+	}
+
+	err = syscall.Exec(tini, tiniArgs, os.Environ())
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/ci/pipelines/develop.yml b/ci/pipelines/develop.yml
index 8f11ed0..9b6ae54 100644
--- a/ci/pipelines/develop.yml
+++ b/ci/pipelines/develop.yml
@@ -16,6 +16,14 @@
 #
 
 ---
+image_resource: &docker-geode-build-image
+  type: docker-image
+  source:
+    username: ((!docker-username))
+    password: ((!docker-password))
+    repository: gcr.io/apachegeode-ci/((!docker-image-name))
+    tag: latest
+
 resource_types:
   - name: gcs-resource
     type: docker-image
@@ -27,6 +35,12 @@ resource_types:
       repository: pcfseceng/email-resource
 
 resources:
+- name: docker-test-image
+  type: docker-image
+  source:
+    username: ((!docker-username))
+    password: ((!docker-password))
+    repository: gcr.io/apachegeode-ci/((!docker-image-name))
 - name: geode
   type: git
   source:
@@ -84,27 +98,281 @@ jobs:
         outputs:
         - name: built-geode
         - name: results
-        image_resource:
-          type: docker-image
-          source:
-            username: ((!docker-username))
-            password: ((!docker-password))
-            repository: gcr.io/apachegeode-ci/apachegeode-build-concourse
-            tag: latest
+        image_resource: *docker-geode-build-image
         params:
           MAINTENANCE_VERSION: ((!maintenance-version))
           SERVICE_ACCOUNT: ((!concourse-gcp-account))
+          PUBLIC_BUCKET: ((!public-bucket))
         run:
           path: geode-ci/ci/scripts/build.sh
-      ensure:
+      on_failure:
         aggregate:
           - put: send-notification-email
             params:
               subject: results/subject
               body: results/body
+      ensure:
+        aggregate:
           - put: geode-build-artifact
             params:
               file: built-geode/geodefiles-*.tgz
           - put: geode-build-version
             params:
               file: results/number
+- name: DistributedTest
+  serial: true
+  public: true
+  plan:
+    - aggregate:
+      - get: geode
+        passed: [Build]
+        trigger: true
+      - get: geode-ci
+      - get: geode-build-version
+        passed: [Build]
+      - get: docker-test-image
+        params:
+          rootfs: true
+    - task: runtests
+      privileged: true
+      timeout: 6h
+      config:
+        inputs:
+          - name: geode
+          - name: geode-ci
+          - name: docker-test-image
+          - name: geode-build-version
+        platform: linux
+        outputs:
+          - name: built-geode
+        image_resource: *docker-geode-build-image
+        params:
+          MAINTENANCE_VERSION: ((!maintenance-version))
+          SERVICE_ACCOUNT: ((!concourse-gcp-account))
+          PUBLIC_BUCKET: ((!public-bucket))
+          PARALLEL_DUNIT: true
+          DUNIT_PARALLEL_FORKS: 7
+        run:
+          args:
+          - distributedTest
+          - distributedtestfiles
+          path: geode-ci/ci/scripts/test-run.sh
+      on_failure:
+        aggregate:
+          - put: send-notification-email
+            params:
+              subject: built-geode/subject
+              body: built-geode/body
+      ensure:
+         aggregate:
+         - task: archive-results
+           config:
+             inputs:
+               - name: geode-ci
+               - name: geode-build-version
+               - name: built-geode
+             platform: linux
+             image_resource: *docker-geode-build-image
+             params:
+               MAINTENANCE_VERSION: ((!maintenance-version))
+               SERVICE_ACCOUNT: ((!concourse-gcp-account))
+               PUBLIC_BUCKET: ((!public-bucket))
+             run:
+               args:
+               - distrbutedTest
+               - distributedtestfiles
+               path: geode-ci/ci/scripts/test-archive.sh
+
+- name: AcceptanceTest
+  serial: true
+  public: true
+  plan:
+    - aggregate:
+      - get: geode
+        passed: [Build]
+        trigger: true
+      - get: geode-ci
+      - get: geode-build-version
+        passed: [Build]
+      - get: docker-test-image
+        params:
+          rootfs: true
+    - task: runtests
+      privileged: true
+      timeout: 6h
+      config:
+        inputs:
+          - name: geode
+          - name: geode-ci
+          - name: docker-test-image
+          - name: geode-build-version
+        platform: linux
+        outputs:
+          - name: built-geode
+        image_resource: *docker-geode-build-image
+        params:
+          MAINTENANCE_VERSION: ((!maintenance-version))
+          SERVICE_ACCOUNT: ((!concourse-gcp-account))
+          PUBLIC_BUCKET: ((!public-bucket))
+          PARALLEL_DUNIT: true
+          DUNIT_PARALLEL_FORKS: 1
+        run:
+          args:
+          - :geode-assembly:acceptanceTest
+          - acceptancetestfiles
+          path: geode-ci/ci/scripts/test-run.sh
+      on_failure:
+        aggregate:
+          - put: send-notification-email
+            params:
+              subject: built-geode/subject
+              body: built-geode/body
+      ensure:
+         aggregate:
+         - task: archive-results
+           config:
+             inputs:
+               - name: geode
+               - name: geode-ci
+               - name: geode-build-version
+               - name: built-geode
+             platform: linux
+             image_resource: *docker-geode-build-image
+             params:
+               MAINTENANCE_VERSION: ((!maintenance-version))
+               SERVICE_ACCOUNT: ((!concourse-gcp-account))
+               PUBLIC_BUCKET: ((!public-bucket))
+             run:
+               args:
+               - :geode-assembly:acceptanceTest
+               - acceptancetestfiles
+               path: geode-ci/ci/scripts/test-archive.sh
+
+- name: IntegrationTest
+  serial: true
+  public: true
+  plan:
+    - aggregate:
+      - get: geode
+        passed: [Build]
+        trigger: true
+      - get: geode-ci
+      - get: geode-build-version
+        passed: [Build]
+      - get: docker-test-image
+        params:
+          rootfs: true
+    - task: runtests
+      privileged: true
+      timeout: 6h
+      config:
+        inputs:
+          - name: geode
+          - name: geode-ci
+          - name: docker-test-image
+          - name: geode-build-version
+        platform: linux
+        outputs:
+          - name: built-geode
+        image_resource: *docker-geode-build-image
+        params:
+          MAINTENANCE_VERSION: ((!maintenance-version))
+          SERVICE_ACCOUNT: ((!concourse-gcp-account))
+          PUBLIC_BUCKET: ((!public-bucket))
+          PARALLEL_DUNIT: true
+          DUNIT_PARALLEL_FORKS: 1
+        run:
+          args:
+          - integrationTest
+          - integrationtestfiles
+          path: geode-ci/ci/scripts/test-run.sh
+      on_failure:
+        aggregate:
+          - put: send-notification-email
+            params:
+              subject: built-geode/subject
+              body: built-geode/body
+      ensure:
+         aggregate:
+         - task: archive-results
+           config:
+             inputs:
+               - name: geode
+               - name: geode-ci
+               - name: geode-build-version
+               - name: built-geode
+             platform: linux
+             image_resource: *docker-geode-build-image
+             params:
+               MAINTENANCE_VERSION: ((!maintenance-version))
+               SERVICE_ACCOUNT: ((!concourse-gcp-account))
+               PUBLIC_BUCKET: ((!public-bucket))
+             run:
+               args:
+               - integrationTest
+               - integrationtestfiles
+               path: geode-ci/ci/scripts/test-archive.sh
+
+- name: FlakyTest
+  serial: true
+  public: true
+  plan:
+    - aggregate:
+      - get: geode
+        passed: [Build]
+        trigger: true
+      - get: geode-ci
+      - get: geode-build-version
+        passed: [Build]
+      - get: docker-test-image
+        params:
+          rootfs: true
+    - task: runtests
+      privileged: true
+      timeout: 6h
+      config:
+        inputs:
+          - name: geode
+          - name: geode-ci
+          - name: docker-test-image
+          - name: geode-build-version
+        platform: linux
+        outputs:
+          - name: built-geode
+        image_resource: *docker-geode-build-image
+        params:
+          MAINTENANCE_VERSION: ((!maintenance-version))
+          SERVICE_ACCOUNT: ((!concourse-gcp-account))
+          PUBLIC_BUCKET: ((!public-bucket))
+        run:
+          args:
+          - flakyTest
+          - flakytestfiles
+          path: geode-ci/ci/scripts/test-run.sh
+      on_failure:
+        aggregate:
+          - put: send-notification-email
+            params:
+              subject: built-geode/subject
+              body: built-geode/body
+      ensure:
+         aggregate:
+         - task: archive-results
+           config:
+             inputs:
+               - name: geode
+               - name: geode-ci
+               - name: geode-build-version
+               - name: built-geode
+             platform: linux
+             image_resource: *docker-geode-build-image
+             params:
+               MAINTENANCE_VERSION: ((!maintenance-version))
+               SERVICE_ACCOUNT: ((!concourse-gcp-account))
+               PUBLIC_BUCKET: ((!public-bucket))
+             run:
+               args:
+               - flakyTest
+               - flakytestfiles
+               path: geode-ci/ci/scripts/test-archive.sh
+
diff --git a/ci/pipelines/docker-images.yml b/ci/pipelines/docker-images.yml
index aa36b85..afa7461 100644
--- a/ci/pipelines/docker-images.yml
+++ b/ci/pipelines/docker-images.yml
@@ -31,7 +31,7 @@ resources:
   source:
     username: ((!docker-username))
     password: ((!docker-password))
-    repository: gcr.io/apachegeode-ci/apachegeode-build-concourse
+    repository: gcr.io/apachegeode-ci/((!docker-image-name))
 
 jobs:
 # apachegeode-build-concourse
diff --git a/ci/scripts/build.sh b/ci/scripts/build.sh
index ae59d7e..3f55fe9 100755
--- a/ci/scripts/build.sh
+++ b/ci/scripts/build.sh
@@ -42,6 +42,11 @@ if [ -z ${SERVICE_ACCOUNT+x} ]; then
   exit 1
 fi
 
+if [ -z ${PUBLIC_BUCKET+x} ]; then
+  echo "PUBLIC_BUCKET is unset. Check your pipeline configuration and make sure this script is called properly."
+  exit 1
+fi
+
 if [ -z ${GEODE_BUILD_VERSION_NUMBER+x} ]; then
   echo "gradle.properties does not seem to contain a valid versionNumber. Please check the source tree."
   exit 1
@@ -81,8 +86,8 @@ GRADLE_EXIT_STATUS=$?
 set -e
 
 popd
-ARTIFACTS_DESTINATION="files.apachegeode-ci.info/builds/${FULL_PRODUCT_VERSION}"
-TEST_RESULTS_DESTINATION="${ARTIFACTS_DESTINATION}/test-results/"
+ARTIFACTS_DESTINATION="${PUBLIC_BUCKET}/builds/${FULL_PRODUCT_VERSION}"
+TEST_RESULTS_DESTINATION="${ARTIFACTS_DESTINATION}/test-results/build/"
 FULL_BUILD_ARCHIVE_DESTINATION="${ARTIFACTS_DESTINATION}/geodefiles-${FULL_PRODUCT_VERSION}.tgz"
 BUILD_ARTIFACTS_FILENAME=geode-build-artifacts-${FULL_PRODUCT_VERSION}.tgz
 BUILD_ARTIFACTS_DESTINATION="${ARTIFACTS_DESTINATION}/${BUILD_ARTIFACTS_FILENAME}"
diff --git a/ci/scripts/test-archive.sh b/ci/scripts/test-archive.sh
new file mode 100755
index 0000000..3099524
--- /dev/null
+++ b/ci/scripts/test-archive.sh
@@ -0,0 +1,121 @@
+#!/usr/local/bin/tini-wrapper /bin/bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+export TERM=${TERM:-dumb}
+export BUILDROOT=$(pwd)
+export DEST_DIR=${BUILDROOT}/built-geode
+export GRADLE_TASK=${1}
+export BASE_FILENAME=${2}
+export TMPDIR=${DEST_DIR}/tmp
+export GEODE_BUILD=${DEST_DIR}/test
+export GEODE_BUILD_VERSION_NUMBER=$(grep "versionNumber *=" geode/gradle.properties | awk -F "=" '{print $2}' | tr -d ' ')
+
+GEODE_BUILD_VERSION_FILE=${BUILDROOT}/geode-build-version/number
+
+if [ ! -e "${GEODE_BUILD_VERSION_FILE}" ]; then
+  echo "${GEODE_BUILD_VERSION_FILE} file does not exist. Concourse is probably not configured correctly."
+  exit 1
+fi
+if [ -z ${MAINTENANCE_VERSION+x} ]; then
+  echo "MAINTENANCE_VERSION is unset. Check your pipeline configuration and make sure this script is called properly."
+  exit 1
+fi
+
+EMAIL_SUBJECT="${BUILDROOT}/built-geode/subject"
+EMAIL_BODY="${BUILDROOT}/built-geode/body"
+
+# Called by trap when the script is exiting
+function error_exit() {
+  echo "Geode unit tests completed in pipeline ${PIPELINE_NAME} with non-zero exit code" > $EMAIL_SUBJECT
+  echo "Pipeline results can be found at:" >$EMAIL_BODY
+  echo "" >>$EMAIL_BODY
+  echo "Concourse: \${ATC_EXTERNAL_URL}/teams/\${BUILD_TEAM_NAME}/pipelines/\${BUILD_PIPELINE_NAME}/jobs/\${BUILD_JOB_NAME}/builds/\${BUILD_NAME}" >>$EMAIL_BODY
+  echo "" >>$EMAIL_BODY
+}
+
+trap error_exit ERR
+
+CONCOURSE_VERSION=$(cat ${GEODE_BUILD_VERSION_FILE})
+CONCOURSE_PRODUCT_VERSION=${CONCOURSE_VERSION%%-*}
+GEODE_PRODUCT_VERSION=${GEODE_BUILD_VERSION_NUMBER}
+CONCOURSE_BUILD_SLUG=${CONCOURSE_VERSION##*-}
+BUILD_ID=${CONCOURSE_VERSION##*.}
+FULL_PRODUCT_VERSION=${GEODE_PRODUCT_VERSION}-${CONCOURSE_BUILD_SLUG}
+
+echo "Concourse VERSION is ${CONCOURSE_VERSION}"
+echo "Geode product VERSION is ${GEODE_PRODUCT_VERSION}"
+echo "Build ID is ${BUILD_ID}"
+
+
+directories_file=${DEST_DIR}/artifact_directories
+mkdir -p ${TMPDIR}
+
+echo "TMPDIR = ${TMPDIR}"
+echo "GRADLE_TASK = ${GRADLE_TASK}"
+echo "BASE_FILENAME = ${BASE_FILENAME}"
+
+gcloud config set account ${SERVICE_ACCOUNT}
+
+
+export FILENAME=${BASE_FILENAME}-${FULL_PRODUCT_VERSION}.tgz
+
+pushd ${GEODE_BUILD}
+
+  set +e
+  ./gradlew combineReports
+  find . -type d -name "reports" > ${directories_file}
+  find . -type d -name "test-results" >> ${directories_file}
+  (find . -type d -name "*Test" | grep "build/[^/]*Test$") >> ${directories_file}
+  find . -name "*-progress*txt" >> ${directories_file}
+  echo "Collecting the following artifacts..."
+  cat ${directories_file}
+  echo ""
+  tar zcf ${DEST_DIR}/${FILENAME} -T ${directories_file}
+popd
+
+ARTIFACTS_DESTINATION="${PUBLIC_BUCKET}/builds/${FULL_PRODUCT_VERSION}"
+TEST_RESULTS_DESTINATION="${ARTIFACTS_DESTINATION}/test-results/${GRADLE_TASK}/"
+TEST_ARTIFACTS_DESTINATION="${ARTIFACTS_DESTINATION}/test-artifacts/"
+FULL_BUILD_ARCHIVE_DESTINATION="${ARTIFACTS_DESTINATION}/geodefiles-${FULL_PRODUCT_VERSION}.tgz"
+BUILD_ARTIFACTS_FILENAME=geode-build-artifacts-${FULL_PRODUCT_VERSION}.tgz
+BUILD_ARTIFACTS_DESTINATION="${ARTIFACTS_DESTINATION}/${BUILD_ARTIFACTS_FILENAME}"
+
+
+if [ ! -d "${GEODE_BUILD}/build/reports/combined" ]; then
+    echo "No tests exist, compile failed."
+    mkdir -p ${GEODE_BUILD}/build/reports/combined
+    echo "<html><head><title>No Test Results Were Captured</title></head><body><h1>No Test Results Were Captured</h1></body></html>" > ${GEODE_BUILD}/build/reports/combined/index.html
+fi
+
+pushd ${GEODE_BUILD}/build/reports/combined
+gsutil -q -m cp -r * gs://${TEST_RESULTS_DESTINATION}
+popd
+
+echo ""
+printf "\033[92m=-=-=-=-=-=-=-=-=-=-=-=-=-=  Test Results Website =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\033[0m\n"
+printf "\033[92mhttp://${TEST_RESULTS_DESTINATION}\033[0m\n"
+printf "\033[92m=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\033[0m\n"
+printf "\n"
+
+gsutil cp ${DEST_DIR}/${FILENAME} gs://${TEST_ARTIFACTS_DESTINATION}
+
+printf "\033[92mTest artifacts from this job are available at:\033[0m\n"
+printf "\n"
+printf "\033[92mhttp://${TEST_ARTIFACTS_DESTINATION}${FILENAME}\033[0m\n"
diff --git a/ci/scripts/test-run.sh b/ci/scripts/test-run.sh
new file mode 100755
index 0000000..bb22b82
--- /dev/null
+++ b/ci/scripts/test-run.sh
@@ -0,0 +1,142 @@
+#!/usr/local/bin/tini-wrapper /bin/bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -x
+set -e
+
+export TERM=${TERM:-dumb}
+export BUILDROOT=$(pwd)
+export DEST_DIR=${BUILDROOT}/built-geode
+export GRADLE_TASK=${1}
+export BASE_FILENAME=${2}
+export TMPDIR=${DEST_DIR}/tmp
+export GEODE_BUILD=${DEST_DIR}/test
+export GEODE_BUILD_VERSION_NUMBER=$(grep "versionNumber *=" geode/gradle.properties | awk -F "=" '{print $2}' | tr -d ' ')
+
+GEODE_BUILD_VERSION_FILE=${BUILDROOT}/geode-build-version/number
+if [ ! -e "${GEODE_BUILD_VERSION_FILE}" ]; then
+  echo "${GEODE_BUILD_VERSION_FILE} file does not exist. Concourse is probably not configured correctly."
+  exit 1
+fi
+if [ -z ${MAINTENANCE_VERSION+x} ]; then
+  echo "MAINTENANCE_VERSION is unset. Check your pipeline configuration and make sure this script is called properly."
+  exit 1
+fi
+
+EMAIL_SUBJECT="${BUILDROOT}/built-geode/subject"
+EMAIL_BODY="${BUILDROOT}/built-geode/body"
+
+# Called by trap when the script is exiting
+function error_exit() {
+  echo "Geode tests completed in pipeline ${PIPELINE_NAME} with non-zero exit code" > $EMAIL_SUBJECT
+  echo "Pipeline results can be found at:" >$EMAIL_BODY
+  echo "" >>$EMAIL_BODY
+  echo "Concourse: \${ATC_EXTERNAL_URL}/teams/\${BUILD_TEAM_NAME}/pipelines/\${BUILD_PIPELINE_NAME}/jobs/\${BUILD_JOB_NAME}/builds/\${BUILD_NAME}" >>$EMAIL_BODY
+  echo "" >>$EMAIL_BODY
+}
+
+trap error_exit ERR
+
+CONCOURSE_VERSION=$(cat ${GEODE_BUILD_VERSION_FILE})
+CONCOURSE_PRODUCT_VERSION=${CONCOURSE_VERSION%%-*}
+GEODE_PRODUCT_VERSION=${GEODE_BUILD_VERSION_NUMBER}
+CONCOURSE_BUILD_SLUG=${CONCOURSE_VERSION##*-}
+BUILD_ID=${CONCOURSE_VERSION##*.}
+FULL_PRODUCT_VERSION=${GEODE_PRODUCT_VERSION}-${CONCOURSE_BUILD_SLUG}
+
+echo "Concourse VERSION is ${CONCOURSE_VERSION}"
+echo "Product VERSION is ${FULL_PRODUCT_VERSION}"
+echo "Build ID is ${BUILD_ID}"
+
+printf "\nUsing the following JDK:"
+java -version
+printf "\n\n"
+
+directories_file=${DEST_DIR}/artifact_directories
+mkdir -p ${TMPDIR}
+
+echo "TMPDIR = ${TMPDIR}"
+echo "GRADLE_TASK = ${GRADLE_TASK}"
+echo "BASE_FILENAME = ${BASE_FILENAME}"
+
+DOCKER_RESOURCE="docker-test-image"
+DOCKER_PIDFILE="/var/run/docker.pid"
+
+if [ -e ${DOCKER_RESOURCE}/rootfs.tar ]; then
+  if [ -e /usr/local/bin/initdocker ]; then
+    echo "Initializing Docker environment..."
+    /usr/local/bin/initdocker || true
+
+    # Stuff like ENV settings don't automatically get imported
+    CHANGE=()
+    for i in $(jq -r '.env | .[]' ${DOCKER_RESOURCE}/metadata.json); do
+      CHANGE+=( $(echo "$i" | awk -F= '{printf("--change \"ENV %s %s\"", $1, $2)}') )
+    done
+
+    REPO=$(cat ${DOCKER_RESOURCE}/repository)
+    echo "Importing Docker image..."
+    eval "docker import ${CHANGE[@]} ${DOCKER_RESOURCE}/rootfs.tar $REPO"
+    DUNIT_DOCKER_IMAGE="-PdunitDockerImage=${REPO}"
+    echo "Docker initialization complete."
+  fi
+fi
+
+DEFAULT_GRADLE_TASK_OPTIONS="--no-daemon -x javadoc -x spotlessCheck"
+
+mkdir -p ${GEODE_BUILD}
+
+pushd geode
+  tar cf - * | (cd ${GEODE_BUILD}; tar xpf -)
+popd
+
+export FILENAME=${BASE_FILENAME}-${FULL_PRODUCT_VERSION}.tgz
+
+if [ -n "${PARALLEL_DUNIT}" ]; then
+  PARALLEL_DUNIT="-PparallelDunit"
+fi
+
+if [ -n "${DUNIT_PARALLEL_FORKS}" ]; then
+  DUNIT_PARALLEL_FORKS="-PdunitParallelForks=${DUNIT_PARALLEL_FORKS}"
+fi
+
+pushd ${GEODE_BUILD}
+  set +e
+  echo "Running tests"
+  set -x
+#    ./gradlew --no-daemon -x javadoc -x spotlessCheck :geode-assembly:acceptanceTest --tests org.apache.geode.management.internal.cli.commands.PutCommandWithJsonTest
+  ./gradlew ${PARALLEL_DUNIT} ${DUNIT_PARALLEL_FORKS} ${DUNIT_DOCKER_IMAGE} \
+      --system-prop "java.io.tmpdir=${TMPDIR}" ${DEFAULT_GRADLE_TASK_OPTIONS} ${GRADLE_TASK}
+  export GRADLE_EXIT_STATUS=$?
+  set +x
+popd
+
+echo "*************************************************************"
+echo "Results information is located in the 'archive-results' task"
+echo "*************************************************************"
+
+echo "GRADLE_EXIT_STATUS is ${GRADLE_EXIT_STATUS}"
+
+
+if [ -e ${DOCKER_PIDFILE} ]; then
+  kill $(cat ${DOCKER_PIDFILE})
+fi
+
+if [[ "${GRADLE_EXIT_STATUS}" != "0" && "${GRADLE_TASK}" == "test" ]]; then
+  error_exit
+fi
+exit ${GRADLE_EXIT_STATUS}

-- 
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <co...@geode.apache.org>'].