Merge "Check that ip of saltmaster is correct in deploy pipeline"
diff --git a/test-salt-formulas-env.groovy b/test-salt-formulas-env.groovy
new file mode 100644
index 0000000..c278538
--- /dev/null
+++ b/test-salt-formulas-env.groovy
@@ -0,0 +1,96 @@
+/**
+ * Test salt formulas pipeline
+ *  DEFAULT_GIT_REF
+ *  DEFAULT_GIT_URL
+ *  CREDENTIALS_ID
+ */
+def common = new com.mirantis.mk.Common()
+def ruby = new com.mirantis.mk.Ruby()
+
+def defaultGitRef, defaultGitUrl
+try {
+  defaultGitRef = DEFAULT_GIT_REF
+  defaultGitUrl = DEFAULT_GIT_URL
+} catch (MissingPropertyException e) {
+  defaultGitRef = null
+  defaultGitUrl = null
+}
+
+def checkouted = false
+
+node("python") {
+  try {
+    stage("checkout") {
+      if (defaultGitRef && defaultGitUrl) {
+        checkouted = gerrit.gerritPatchsetCheckout(defaultGitUrl, defaultGitRef, "HEAD", CREDENTIALS_ID)
+      } else {
+        throw new Exception("Cannot checkout gerrit patchset, DEFAULT_GIT_REF is null")
+      }
+    }
+    stage("test") {
+      if (checkouted) {
+        sh("make clean")
+        sh("[ $SALT_VERSION != 'latest' ] || export SALT_VERSION=''; make test")
+      }
+    }
+    stage("kitchen") {
+      if (checkouted) {
+        if (fileExists(".kitchen.yml")) {
+          common.infoMsg(".kitchen.yml found, running kitchen tests")
+          ruby.ensureRubyEnv()
+          if (fileExists(".travis.yml")) {
+            common.infoMsg(".travis.yml found, running custom kitchen init")
+            def kitchenConfigYML = readYaml(file: ".travis.yml")
+            def kitchenInit = kitchenConfigYML["install"]
+            def kitchenInstalled = false
+            if (kitchenInit && !kitchenInit.isEmpty()) {
+              for (int i = 0; i < kitchenInit.size(); i++) {
+                if (kitchenInit[i].trim().startsWith("test -e Gemfile")) { //found Gemfile config
+                  common.infoMsg("Custom Gemfile configuration found, using them")
+                  ruby.installKitchen(kitchenInit[i].trim())
+                  kitchenInstalled = true
+                }
+              }
+            }
+            if (!kitchenInstalled) {
+              ruby.installKitchen()
+            }
+          } else {
+            common.infoMsg(".travis.yml not found, running default kitchen init")
+            ruby.installKitchen()
+          }
+          common.infoMsg("Running part of kitchen test")
+          if (common.validInputParam(KITCHEN_ENV)) {
+            def cleanEnv = KITCHEN_ENV.replaceAll("\\s?SUITE=[^\\s]*", "")
+            def suitePattern = java.util.regex.Pattern.compile("\\s?SUITE=([^\\s]*)")
+            def suiteMatcher = suitePattern.matcher(KITCHEN_ENV)
+            if (suiteMatcher.find()) {
+              def suite = suiteMatcher.group(1)
+              def cleanSuite = suite.replaceAll("_", "-")
+              common.infoMsg("Running kitchen test with environment:" + filteredEnvs.trim())
+              ruby.runKitchenTests(cleanEnv, cleanSuite)
+            } else {
+              common.warningMsg("No SUITE was found. Running with all suites.")
+              ruby.runKitchenTests(cleanEnv, "")
+            }
+          } else {
+            throw new Exception("KITCHEN_ENV parameter is empty or invalid. This may indicate wrong env settings of initial test job or .travis.yml file.")
+          }
+        } else {
+          throw new Exception(".kitchen.yml file not found, no kitchen tests triggered.")
+        }
+      }
+    }
+  } catch (Throwable e) {
+    // If there was an error or exception thrown, the build failed
+    currentBuild.result = "FAILURE"
+    ruby.runKitchenCommand("destroy")
+    throw e
+  } finally {
+    if (currentBuild.result == "FAILURE" && fileExists(".kitchen/logs/kitchen.log")) {
+      common.errorMsg("----------------KITCHEN LOG:---------------")
+      println readFile(".kitchen/logs/kitchen.log")
+    }
+    common.sendNotification(currentBuild.result, "", ["slack"])
+  }
+}
\ No newline at end of file
diff --git a/test-salt-formulas-pipeline.groovy b/test-salt-formulas-pipeline.groovy
index 1fb62ad..32a6538 100644
--- a/test-salt-formulas-pipeline.groovy
+++ b/test-salt-formulas-pipeline.groovy
@@ -16,116 +16,122 @@
   gerritRef = null
 }
 
+def parallelGroupSize
+try {
+  parallelGroupSize = Integer.valueOf(PARALLEL_GROUP_SIZE)
+} catch (MissingPropertyException e) {
+  parallelGroupSize = 4
+}
+
 def defaultGitRef, defaultGitUrl
 try {
-    defaultGitRef = DEFAULT_GIT_REF
-    defaultGitUrl = DEFAULT_GIT_URL
+  defaultGitRef = DEFAULT_GIT_REF
+  defaultGitUrl = DEFAULT_GIT_URL
 } catch (MissingPropertyException e) {
-    defaultGitRef = null
-    defaultGitUrl = null
+  defaultGitRef = null
+  defaultGitUrl = null
 }
 
 def checkouted = false
 
 node("python") {
-  try{
+  try {
     stage("checkout") {
       if (gerritRef) {
         // job is triggered by Gerrit
         def gerritChange = gerrit.getGerritChange(GERRIT_NAME, GERRIT_HOST, GERRIT_CHANGE_NUMBER, CREDENTIALS_ID, true)
         // test if gerrit change is already Verified
-        if(gerrit.patchsetHasApproval(gerritChange.currentPatchSet,"Verified","+")){
+        if (gerrit.patchsetHasApproval(gerritChange.currentPatchSet, "Verified", "+")) {
           common.successMsg("Gerrit change ${GERRIT_CHANGE_NUMBER} patchset ${GERRIT_PATCHSET_NUMBER} already has Verified, skipping tests") // do nothing
-        // test WIP contains in commit message
-        }else if(gerritChange.commitMessage.contains("WIP")){
+          // test WIP contains in commit message
+        } else if (gerritChange.commitMessage.contains("WIP")) {
           common.successMsg("Commit message contains WIP, skipping tests") // do nothing
-        }else{
+        } else {
           // test if change aren't already merged
           def merged = gerritChange.status == "MERGED"
-          if(!merged){
-            checkouted = gerrit.gerritPatchsetCheckout ([
-              credentialsId : CREDENTIALS_ID
+          if (!merged) {
+            checkouted = gerrit.gerritPatchsetCheckout([
+              credentialsId: CREDENTIALS_ID
             ])
-          } else{
+          } else {
             common.successMsg("Change ${GERRIT_CHANGE_NUMBER} is already merged, no need to test them")
           }
         }
-      } else if(defaultGitRef && defaultGitUrl) {
-          checkouted = gerrit.gerritPatchsetCheckout(defaultGitUrl, defaultGitRef, "HEAD", CREDENTIALS_ID)
+      } else if (defaultGitRef && defaultGitUrl) {
+        checkouted = gerrit.gerritPatchsetCheckout(defaultGitUrl, defaultGitRef, "HEAD", CREDENTIALS_ID)
       } else {
         throw new Exception("Cannot checkout gerrit patchset, GERRIT_REFSPEC and DEFAULT_GIT_REF is null")
       }
     }
     stage("test") {
-      if(checkouted){
+      if (checkouted) {
         sh("make clean")
         sh("[ $SALT_VERSION != 'latest' ] || export SALT_VERSION=''; make test")
       }
     }
     stage("kitchen") {
-      if(checkouted){
+      if (checkouted) {
         if (fileExists(".kitchen.yml")) {
           common.infoMsg(".kitchen.yml found, running kitchen tests")
           ruby.ensureRubyEnv()
           def kitchenEnvs = []
           def filteredEnvs = []
-          if(fileExists(".travis.yml")){
-            common.infoMsg(".travis.yml found, running custom kitchen init")
+          if (fileExists(".travis.yml")) {
+            common.infoMsg(".travis.yml file found.")
             def kitchenConfigYML = readYaml(file: ".travis.yml")
-            if(kitchenConfigYML.containsKey("env")){
-              kitchenEnvs=kitchenConfigYML["env"]
-            }
-            def kitchenInit = kitchenConfigYML["install"]
-            def kitchenInstalled = false
-            if(kitchenInit && !kitchenInit.isEmpty()){
-              for(int i=0; i<kitchenInit.size(); i++){
-                if(kitchenInit[i].trim().startsWith("test -e Gemfile")){ //found Gemfile config
-                  common.infoMsg("Custom Gemfile configuration found, using them")
-                  ruby.installKitchen(kitchenInit[i].trim())
-                  kitchenInstalled = true
-                }
-              }
-            }
-            if(!kitchenInstalled){
-              ruby.installKitchen()
-            }
-          }else{
-            common.infoMsg(".travis.yml not found, running default kitchen init")
-            ruby.installKitchen()
-          }
-          common.infoMsg("Running kitchen testing, parallel mode: " + KITCHEN_TESTS_PARALLEL.toBoolean())
-
-          if(CUSTOM_KITCHEN_ENVS != null && CUSTOM_KITCHEN_ENVS != ''){
-              filteredEnvs = CUSTOM_KITCHEN_ENVS.tokenize('\n')
-            } else {
-              filteredEnvs = ruby.filterKitchenEnvs(kitchenEnvs).unique()
-            }
-            // Allow custom filteredEnvs in case of empty kitchenEnvs
-          if((kitchenEnvs && !kitchenEnvs.isEmpty() && !filteredEnvs.isEmpty()) || ((kitchenEnvs==null || kitchenEnvs=='') && !filteredEnvs.isEmpty())){
-            for(int i=0; i<filteredEnvs.size(); i++){
-              common.infoMsg("Found " + filteredEnvs.size() + " environment, kitchen running with env number " + (i+1) + ": " + filteredEnvs[i].trim())
-              ruby.runKitchenTests(filteredEnvs[i].trim(), KITCHEN_TESTS_PARALLEL.toBoolean())
+            if (kitchenConfigYML.containsKey("env")) {
+              kitchenEnvs = kitchenConfigYML["env"]
             }
           } else {
-            ruby.runKitchenTests("", KITCHEN_TESTS_PARALLEL.toBoolean())
+            common.warningMsg(".travis.yml file not found, suites must be passed via CUSTOM_KITCHEN_ENVS parameter.")
           }
-        } else {
-          common.infoMsg(".kitchen.yml not found")
+          common.infoMsg("Running kitchen testing in parallel mode")
+          if (CUSTOM_KITCHEN_ENVS != null && CUSTOM_KITCHEN_ENVS != '') {
+            kitchenEnvs = CUSTOM_KITCHEN_ENVS.tokenize('\n')
+            common.infoMsg("CUSTOM_KITCHEN_ENVS not empty. Running with custom enviroments: ${kitchenEnvs}")
+          }
+          if (kitchenEnvs != null && kitchenEnvs != '') {
+            common.infoMsg("Found " + kitchenEnvs.size() + " environment(s)")
+            for (int i = 0; i < kitchenEnvs.size(); i++) {
+              def acc = 0
+              if (acc >= parallelGroupSize) {
+                parallel kitchenTestRuns
+                kitchenTestRuns = [: ]
+                acc = 0
+              }
+              def testEnv = kitchenEnvs[i]
+              kitchenTestRuns[testEnv] = {
+                build job: "test-salt-formulas-env", parameters: [
+                  [$class: 'StringParameterValue', name: 'CREDENTIALS_ID', value: CREDENTIALS_ID],
+                  [$class: 'StringParameterValue', name: 'KITCHEN_ENV', value: testEnv],
+                  [$class: 'StringParameterValue', name: 'DEFAULT_GIT_REF', value: DEFAULT_GIT_REF],
+                  [$class: 'StringParameterValue', name: 'DEFAULT_GIT_URL', value: DEFAULT_GIT_URL],
+                  [$class: 'StringParameterValue', name: 'SALT_OPTS', value: SALT_OPTS],
+                  [$class: 'StringParameterValue', name: 'SALT_VERSION', value: SALT_VERSION]
+                ]
+              }
+              acc++;
+            }
+            if (acc != 0) {
+              parallel kitchenTestRuns
+            }
+          } else {
+            common.warningMsg(".kitchen.yml file not found, no kitchen tests triggered.")
+          }
         }
       }
     }
   } catch (Throwable e) {
-     // If there was an error or exception thrown, the build failed
-     currentBuild.result = "FAILURE"
-     currentBuild.description = currentBuild.description ? e.message + " " + currentBuild.description : e.message
-     ruby.runKitchenCommand("destroy")
-     throw e
+    // If there was an error or exception thrown, the build failed
+    currentBuild.result = "FAILURE"
+    currentBuild.description = currentBuild.description ? e.message + " " + currentBuild.description : e.message
+    ruby.runKitchenCommand("destroy")
+    throw e
   } finally {
-     if(currentBuild.result == "FAILURE" && fileExists(".kitchen/logs/kitchen.log")){
-        common.errorMsg("----------------KITCHEN LOG:---------------")
-        println readFile(".kitchen/logs/kitchen.log")
-     }
-     common.sendNotification(currentBuild.result,"",["slack"])
+    if (currentBuild.result == "FAILURE" && fileExists(".kitchen/logs/kitchen.log")) {
+      common.errorMsg("----------------KITCHEN LOG:---------------")
+      println readFile(".kitchen/logs/kitchen.log")
+    }
+    common.sendNotification(currentBuild.result, "", ["slack"])
   }
-}
-
+}
\ No newline at end of file