#!groovy
/*
 * 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 groovy.util.CliBuilder

/*
 * Scripting functions to make writing a test similar to the quickstart
 * instructions from https://beam.apache.org/get-started/quickstart-java/
 */
class TestScripts {

   // Global state to maintain when running the steps
   class var {
     static File startDir
     static File curDir
     static String repoUrl
     static String ver
     static String gcpProject
     static String gcsBucket
     static String bqDataset
     static String pubsubTopic
   }

   def TestScripts(String[] args) {
     def cli = new CliBuilder()
     cli.ver(args:1, 'SDL Version')
     cli.repourl(args:1, 'Repository URL')
     cli.gcpProject(args:1, 'Google Cloud Project')
     cli.gcsBucket(args:1, 'Google Cloud Storage Bucket')
     cli.bqDataset(args:1, "BigQuery Dataset")
     cli.pubsubTopic(args:1, "PubSub Topic")

     def options = cli.parse(args)
     var.repoUrl = options.repourl
     var.ver = options.ver
     println "Repository URL: ${var.repoUrl}"
     println "Version: ${var.ver}"
     if (options.gcpProject) {
       var.gcpProject = options.gcpProject
       println "GCS Project: ${var.gcpProject}"
     }
     if (options.gcsBucket) {
       var.gcsBucket = options.gcsBucket
       println "GCS Storage bucket: ${var.gcsBucket}"
     }
     if (options.bqDataset) {
         var.bqDataset = options.bqDataset
         println "BigQuery Dataset: ${var.bqDataset}"
     }
     if (options.pubsubTopic) {
         var.pubsubTopic = options.pubsubTopic
         println "PubSub Topic: ${var.pubsubTopic}"
     }
   }

   def ver() {
     return var.ver
   }

   def gcpProject() {
     return var.gcpProject
   }

   def gcsBucket() {
     return var.gcsBucket
   }

   def bqDataset() {
     return var.bqDataset
   }

   def pubsubTopic() {
     return var.pubsubTopic
   }

   // Both documents the overal scenario and creates a clean temp directory
   def describe(String desc) {
     var.startDir = File.createTempDir()
     var.startDir.deleteOnExit()
     var.curDir = var.startDir
     print "**************************************\n* Scenario: ${desc}\n**************************************\n"
   }

   // Just document the intention of a set of steps
   def intent(String desc) {
     print "\n**************************************\n* Test: ${desc}\n**************************************\n\n"
   }

   def success(String desc) {
     print "\n**************************************\n* SUCCESS: ${desc}\n**************************************\n\n"
   }

   // Run a command
   public String run(String cmd) {
     println cmd
     if (cmd.startsWith("cd ")) {
       _chdir(cmd.substring(3))
       return ""
     } else if (cmd.startsWith("mvn ")) {
       return _mvn(cmd.substring(4))
     } else {
       return _execute(cmd)
     }
   }

   // Check for expected results in actual stdout from previous command, if fails, log errors then exit.
   public void see(String expected, String actual) {
     if (!actual.contains(expected)) {
       var.startDir.deleteDir()
       println "Cannot find ${expected} in ${actual}"
       error("Cannot find expected text")
     }
     println "Verified $expected"
   }

   // Check if there are one or more matches in stdout of the last command.
   public boolean seeAnyOf(List<String> expecteds, String actual) {
     for (String expected: expecteds) {
       if(actual.contains(expected)) {
         println "Verified $expected"
         return true
       }
     }
     println "Cannot find ${expecteds} in text"
     return false
   }

   // Cleanup and print success
   public void done() {
     var.startDir.deleteDir()
     println "[SUCCESS]"
     System.exit(0)
   }

   // Run a single command, capture output, verify return code is 0
   private String _execute(String cmd) {
     def shell = "sh -c cmd".split(' ')
     shell[2] = cmd
     def pb = new ProcessBuilder(shell)
     pb.directory(var.curDir)
     pb.redirectErrorStream(true)
     def proc = pb.start()
     String output_text = ""
     def text = StringBuilder.newInstance()
     proc.inputStream.eachLine {
       println it
       text.append(it + "\n")
     }
     proc.waitFor()
     output_text = text.toString().trim()
     if (proc.exitValue() != 0) {
       println output_text
       error("Failed command")
     }
     return output_text
   }

   // Change directory
   private void _chdir(String subdir) {
     var.curDir = new File(var.curDir.absolutePath, subdir)
     if (!var.curDir.exists()) {
       error("Directory ${var.curDir} not found")
     }
   }

   // Run a maven command, setting up a new local repository and a settings.xml with a custom repository
   private String _mvn(String args) {
     def m2 = new File(var.startDir, ".m2/repository")
     m2.mkdirs()
     def settings = new File(var.startDir, "settings.xml")
     settings.write """
       <settings>
         <localRepository>${m2.absolutePath}</localRepository>
           <profiles>
             <profile>
               <id>testrel</id>
                 <repositories>
                   <repository>
                     <id>test.release</id>
                     <url>${var.repoUrl}</url>
                   </repository>
                 </repositories>
               </profile>
             </profiles>
        </settings>
        """
       def cmd = "mvn ${args} -s ${settings.absolutePath} -Ptestrel -B"
       String path = System.getenv("PATH");
       // Set the path on jenkins executors to use a recent maven
       // MAVEN_HOME is not set on some executors, so default to 3.5.2
       String maven_home = System.getenv("MAVEN_HOME") ?: '/home/jenkins/tools/maven/apache-maven-3.5.4'
       println "Using maven ${maven_home}"
       def mvnPath = "${maven_home}/bin"
       def setPath = "export PATH=${mvnPath}:${path} && "
       return _execute(setPath + cmd)
   }

   // Clean up and report error
   public void error(String text) {
     var.startDir.deleteDir()
     println "[ERROR] $text"
     System.exit(1)
   }
}
