From d080bae2a144cfeaec9701392a8d7f39bfc34acb Mon Sep 17 00:00:00 2001 From: zpencer Date: Wed, 29 Nov 2017 11:20:15 -0800 Subject: [PATCH] gae-interop-testing: kokoro script to run interop tests in GAE (#3731) --- buildscripts/kokoro/gae-interop.sh | 69 ++++++++++++++++++++++- gae-interop-testing/gae-jdk7/build.gradle | 55 ++++++++++++++---- gae-interop-testing/gae-jdk8/build.gradle | 53 +++++++++++++---- 3 files changed, 154 insertions(+), 23 deletions(-) diff --git a/buildscripts/kokoro/gae-interop.sh b/buildscripts/kokoro/gae-interop.sh index 2665f36a0d..6ea604e74d 100755 --- a/buildscripts/kokoro/gae-interop.sh +++ b/buildscripts/kokoro/gae-interop.sh @@ -1,3 +1,68 @@ -#!/bin/sh +#!/bin/bash -# An empty placeholder shellscript +set -exu -o pipefail + +KOKORO_GAE_SERVICE="java-gae-interop-test" + +# We deploy as different versions of a single service, this way any stale +# lingering deploys can be easily cleaned up by purging all running versions +# of this service. +KOKORO_GAE_APP_VERSION=$(hostname) + +# A dummy version that can be the recipient of all traffic, so that the kokoro test version can be +# set to 0 traffic. This is a requirement in order to delete it. +DUMMY_DEFAULT_VERSION='dummy-default' + +function cleanup() { + echo "Performing cleanup now." + gcloud app services set-traffic $KOKORO_GAE_SERVICE --quiet --splits $DUMMY_DEFAULT_VERSION=1.0 + gcloud app services delete $KOKORO_GAE_SERVICE --version $KOKORO_GAE_APP_VERSION --quiet +} +trap cleanup SIGHUP SIGINT SIGTERM EXIT + +cd ./github/grpc-java + +## +## Deploy the dummy 'default' version of the service +## +echo " + + true + $KOKORO_GAE_SERVICE + java8 + +" > ./gae-interop-testing/gae-jdk8/src/main/webapp/WEB-INF/appengine-web.xml +cat ./gae-interop-testing/gae-jdk8/src/main/webapp/WEB-INF/appengine-web.xml +# Deploy the dummy 'default' version. It doesn't matter if we race with other kokoro runs. +# We only require that it exists when cleanup() is called. +if [[ $(gcloud app versions describe $DUMMY_DEFAULT_VERSION --service=$KOKORO_GAE_SERVICE) != 0 ]]; then + ./gradlew --stacktrace -DgaeDeployVersion=$DUMMY_DEFAULT_VERSION -DgaeStopPreviousVersion=false -DgaePromote=false -PskipCodegen=true :grpc-gae-interop-testing-jdk8:appengineDeploy +fi + +## +## Begin JDK8 test +## +echo " + + true + $KOKORO_GAE_SERVICE + java8 + +" > ./gae-interop-testing/gae-jdk8/src/main/webapp/WEB-INF/appengine-web.xml +cat ./gae-interop-testing/gae-jdk8/src/main/webapp/WEB-INF/appengine-web.xml +# Deploy and test the real app (jdk8) +./gradlew --stacktrace -DgaeDeployVersion=$KOKORO_GAE_APP_VERSION -DgaeStopPreviousVersion=false -DgaePromote=false -PskipCodegen=true :grpc-gae-interop-testing-jdk8:runInteropTestRemote + +## +## Begin JDK7 test +## +echo " + + true + $KOKORO_GAE_SERVICE + java7 + +" > ./gae-interop-testing/gae-jdk7/src/main/webapp/WEB-INF/appengine-web.xml +cat ./gae-interop-testing/gae-jdk7/src/main/webapp/WEB-INF/appengine-web.xml +# Deploy and test the real app (jdk7) +./gradlew --stacktrace -DgaeDeployVersion=$KOKORO_GAE_APP_VERSION -DgaeStopPreviousVersion=false -DgaePromote=false -PskipCodegen=true :grpc-gae-interop-testing-jdk7:runInteropTestRemote diff --git a/gae-interop-testing/gae-jdk7/build.gradle b/gae-interop-testing/gae-jdk7/build.gradle index e13578fa20..902eece88e 100644 --- a/gae-interop-testing/gae-jdk7/build.gradle +++ b/gae-interop-testing/gae-jdk7/build.gradle @@ -55,8 +55,12 @@ appengine { // App Engine tasks configuration } deploy { // deploy configuration - stopPreviousVersion = true // default - stop the current version - promote = true // default - & make this the current version + // default - stop the current version + stopPreviousVersion = System.getProperty('gaeStopPreviousVersion') ?: true + // default - make this the current version + promote = System.getProperty('gaePromote') ?: true + // Use -DgaeDeployVersion if set, otherwise the version is null and the plugin will generate it + version = System.getProperty('gaeDeployVersion') } } // [END model] @@ -67,7 +71,8 @@ version = '1.0-SNAPSHOT' // Version in generated output sourceCompatibility = 1.7 targetCompatibility = 1.7 -def getAppName() { +/** Returns the service name. */ +String getGaeProject() { def stream = new ByteArrayOutputStream() exec { executable 'gcloud' @@ -77,21 +82,49 @@ def getAppName() { return stream.toString().trim() } +String getService(java.nio.file.Path projectPath) { + Node xml = new XmlParser().parse(projectPath.resolve("src/main/webapp/WEB-INF/appengine-web.xml").toFile()) + if (xml.service.isEmpty()) { + return null + } else { + return xml.service.text() + } +} + +String getAppUrl(String project, String service, String version) { + if (version != null && service != null) { + return "http://${version}.${service}.${project}.appspot.com" + } else { + return "http://${project}.appspot.com" + } +} + task runInteropTestRemote(dependsOn: 'appengineDeploy') { doLast { // give remote app some time to settle down - sleep(5000) + sleep(20000) - def appName = getAppName() + def appUrl = getAppUrl( + getGaeProject(), + getService(project.getProjectDir().toPath()), + System.getProperty('gaeDeployVersion')) + logger.log(LogLevel.INFO, "the appURL=" + appUrl) def client = new com.squareup.okhttp.OkHttpClient() // The test suite can take a while to run client.setReadTimeout(3, java.util.concurrent.TimeUnit.MINUTES) - // The '?jdk7' argument is ignored by the server, it exists only to tag the request log entry - def request = new com.squareup.okhttp.Request.Builder() - .url("http://${appName}.appspot.com/?jdk7").build() - def result = client.newCall(request).execute() - if (result.code() != 200) { - throw new GradleException("Interop test failed: " + result.body().string()) + // The '?jdk8' argument is ignored by the server, it exists only to tag the request log entry + def interopRequest = new com.squareup.okhttp.Request.Builder() + .url("${appUrl}/?jdk7").build() + + // Retry in case GAE is slow and times out + int maxRetries = 5 + def result = null + for (int attempt = 0; attempt < maxRetries; attempt++) { + result = client.newCall(interopRequest).execute() + if (result.code() == 200) { + return + } } + throw new GradleException("Interop test failed: " + result?.body()?.string()) } } diff --git a/gae-interop-testing/gae-jdk8/build.gradle b/gae-interop-testing/gae-jdk8/build.gradle index 9fa34116e1..a24b4c720f 100644 --- a/gae-interop-testing/gae-jdk8/build.gradle +++ b/gae-interop-testing/gae-jdk8/build.gradle @@ -56,8 +56,12 @@ appengine { // App Engine tasks configuration } deploy { // deploy configuration - stopPreviousVersion = true // default - stop the current version - promote = true // default - & make this the current version + // default - stop the current version + stopPreviousVersion = System.getProperty('gaeStopPreviousVersion') ?: true + // default - make this the current version + promote = System.getProperty('gaePromote') ?: true + // Use -DgaeDeployVersion if set, otherwise the version is null and the plugin will generate it + version = System.getProperty('gaeDeployVersion') } } // [END model] @@ -68,7 +72,8 @@ version = '1.0-SNAPSHOT' // Version in generated output sourceCompatibility = 1.8 targetCompatibility = 1.8 -def getAppName() { +/** Returns the service name. */ +String getGaeProject() { def stream = new ByteArrayOutputStream() exec { executable 'gcloud' @@ -78,17 +83,38 @@ def getAppName() { return stream.toString().trim() } +String getService(java.nio.file.Path projectPath) { + Node xml = new XmlParser().parse(projectPath.resolve("src/main/webapp/WEB-INF/appengine-web.xml").toFile()) + if (xml.service.isEmpty()) { + return null + } else { + return xml.service.text() + } +} + +String getAppUrl(String project, String service, String version) { + if (version != null && service != null) { + return "http://${version}.${service}.${project}.appspot.com" + } else { + return "http://${project}.appspot.com" + } +} + task runInteropTestRemote(dependsOn: 'appengineDeploy') { doLast { // give remote app some time to settle down - sleep(5000) + sleep(20000) - def appName = getAppName() + def appUrl = getAppUrl( + getGaeProject(), + getService(project.getProjectDir().toPath()), + System.getProperty('gaeDeployVersion')) + logger.log(LogLevel.INFO, "the appURL=" + appUrl) def client = new com.squareup.okhttp.OkHttpClient() // The '?jdk8' argument is ignored by the server, it exists only to tag the request log entry client.setReadTimeout(30, java.util.concurrent.TimeUnit.SECONDS) def request = new com.squareup.okhttp.Request.Builder() - .url("http://${appName}.appspot.com/long_lived_channel?jdk8").build() + .url("${appUrl}/long_lived_channel?jdk8").build() def result1 = client.newCall(request).execute() def result2 = client.newCall(request).execute() if (result1.code() != 200 || result2.code() != 200) { @@ -99,10 +125,17 @@ task runInteropTestRemote(dependsOn: 'appengineDeploy') { client.setReadTimeout(3, java.util.concurrent.TimeUnit.MINUTES) // The '?jdk8' argument is ignored by the server, it exists only to tag the request log entry def interopRequest = new com.squareup.okhttp.Request.Builder() - .url("http://${appName}.appspot.com/?jdk8").build() - def result = client.newCall(interopRequest).execute() - if (result.code() != 200) { - throw new GradleException("Interop test failed: " + result.body().string()) + .url("${appUrl}/?jdk8").build() + + // Retry in case GAE is slow and times out + int maxRetries = 5 + def result = null + for (int attempt = 0; attempt < maxRetries; attempt++) { + result = client.newCall(interopRequest).execute() + if (result.code() == 200) { + return + } } + throw new GradleException("Interop test failed: " + result?.body()?.string()) } }