// Copyright 2017 The gRPC Authors
//
//  Licensed 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.

buildscript {
    // Configuration for building
    repositories {
        maven { // The google mirror is less flaky than mavenCentral()
            url "https://maven-central.storage-download.googleapis.com/maven2/" }
    }
    dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.3.0'
        classpath 'com.squareup.okhttp:okhttp:2.7.4'
    }
}

plugins {
    id "java"
    id "war"
}

description = 'gRPC: gae interop testing (jdk8)'

repositories {
    // repositories for Jar's you access in your code
    mavenLocal()
    maven { // The google mirror is less flaky than mavenCentral()
        url "https://maven-central.storage-download.googleapis.com/maven2/" }
}

apply plugin: 'com.google.cloud.tools.appengine'  // App Engine tasks

dependencies {
    providedCompile group: 'javax.servlet', name: 'servlet-api', version:'2.5'
    runtimeOnly 'com.google.appengine:appengine-api-1.0-sdk:1.9.59'
    implementation project(':grpc-netty')
    implementation project(":grpc-stub")
    implementation (project(':grpc-interop-testing')) {
        // Avoid grpc-netty-shaded dependency
        exclude group: 'io.grpc', module: 'grpc-alts'
        exclude group: 'io.grpc', module: 'grpc-xds'
    }
    implementation libraries.junit
    implementation libraries.protobuf
    runtimeOnly libraries.netty_tcnative
}

compileJava {
    // Disable "No processor claimed any of these annotations: org.junit.Ignore"
    options.compilerArgs += ["-Xlint:-processing"]
}

def createDefaultVersion() {
    return new java.text.SimpleDateFormat("yyyyMMdd't'HHmmss").format(new Date())
}

// [START model]
appengine {
    // App Engine tasks configuration
    run {      // local (dev_appserver) configuration (standard environments only)
        port = 8080                 // default
    }

    deploy {
        // deploy configuration
        projectId = 'GCLOUD_CONFIG'
        // default - stop the current version
        stopPreviousVersion = System.getProperty('gaeStopPreviousVersion') ?: true
        // default - do not make this the promoted version
        promote = System.getProperty('gaePromote') ?: false
        // Use -DgaeDeployVersion if set, otherwise the version is null and the plugin will generate it
        version = System.getProperty('gaeDeployVersion', createDefaultVersion())
    }
}
// [END model]

group = 'io.grpc'   // Generated output GroupId
version = '1.0-SNAPSHOT'          // Version in generated output

sourceCompatibility = 1.8
targetCompatibility = 1.8

/** Returns the service name. */
String getGaeProject() {
    def stream = new ByteArrayOutputStream()
    exec {
        executable 'gcloud'
        args = [
            'config',
            'get-value',
            'project'
        ]
        standardOutput = stream
    }
    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 "default"
    } else {
        return xml.service.text()
    }
}

String getAppUrl(String project, String service, String version) {
    return "http://${version}.${service}.${project}.appspot.com"
}

task runInteropTestRemote(dependsOn: 'appengineDeploy') {
    doLast {
        // give remote app some time to settle down
        sleep(20000)

        def appUrl = getAppUrl(
                getGaeProject(),
                getService(project.getProjectDir().toPath()),
                appengine.deploy.version)
        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("${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) {
            throw new GradleException("Unable to reuse same channel across requests")
        }

        // The test suite can take a while to run
        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("${appUrl}/?jdk8").build()

        // Retry in case GAE is slow and times out
        int maxRetries = 5
        String result = null
        Throwable caught = null
        for (int attempt = 0; attempt < maxRetries; attempt++) {
            try {
                def response = client.newCall(interopRequest).execute()
                result = response.body().string()
                project.println(result)
                if (response.code() == 200) {
                    return
                }
            } catch (Throwable t) {
                caught = t
                logger.log(LogLevel.ERROR, "caught exception. will retry if possible", t)
            }
        }
        throw new GradleException("Interop test failed:\nthrowable:${caught}")
    }
}
