diff --git a/src/com/sap/piper/ConfigurationHelper.groovy b/src/com/sap/piper/ConfigurationHelper.groovy
index b8e61d2d0..88ee6af1d 100644
--- a/src/com/sap/piper/ConfigurationHelper.groovy
+++ b/src/com/sap/piper/ConfigurationHelper.groovy
@@ -1,5 +1,7 @@
package com.sap.piper
+import com.cloudbees.groovy.cps.NonCPS
+
class ConfigurationHelper implements Serializable {
static ConfigurationHelper loadStepDefaults(Script step){
return new ConfigurationHelper(step)
@@ -96,13 +98,19 @@ class ConfigurationHelper implements Serializable {
return this
}
- Map use(){ return config }
+ @NonCPS // required because we have a closure in the
+ // method body that cannot be CPS transformed
+ Map use(){
+ MapUtils.traverse(config, { v -> (v instanceof GString) ? v.toString() : v })
+ return config
+ }
ConfigurationHelper(Map config = [:]){
this.config = config
}
def getConfigProperty(key) {
+ use()
return getConfigPropertyNested(config, key)
}
diff --git a/src/com/sap/piper/MapUtils.groovy b/src/com/sap/piper/MapUtils.groovy
index de4ad2096..784a281e7 100644
--- a/src/com/sap/piper/MapUtils.groovy
+++ b/src/com/sap/piper/MapUtils.groovy
@@ -38,4 +38,28 @@ class MapUtils implements Serializable {
return result
}
+
+ /**
+ * @param m The map to which the changed denoted by closure strategy
+ * should be applied.
+ * The strategy is also applied to all sub-maps contained as values
+ * in m
in a recursive manner.
+ * @param strategy Strategy applied to all non-map entries
+ */
+ @NonCPS
+ static void traverse(Map m, Closure strategy) {
+
+ def updates = [:]
+ for(def e : m.entrySet()) {
+ if(isMap(e.value)) {
+ traverse(e.getValue(), strategy)
+ }
+ else {
+ // do not update the map while it is traversed. Depending
+ // on the map implementation the behavior is undefined.
+ updates.put(e.getKey(), strategy(e.getValue()))
+ }
+ }
+ m.putAll(updates)
+ }
}
diff --git a/test/groovy/CloudFoundryDeployTest.groovy b/test/groovy/CloudFoundryDeployTest.groovy
index afabbd3af..f4e5d7326 100644
--- a/test/groovy/CloudFoundryDeployTest.groovy
+++ b/test/groovy/CloudFoundryDeployTest.groovy
@@ -6,6 +6,7 @@ import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import org.yaml.snakeyaml.Yaml
import util.BasePiperTest
+import util.JenkinsCredentialsRule
import util.JenkinsEnvironmentRule
import util.JenkinsDockerExecuteRule
import util.JenkinsLoggingRule
@@ -42,28 +43,9 @@ class CloudFoundryDeployTest extends BasePiperTest {
.around(jwfr)
.around(jedr)
.around(jer)
+ .around(new JenkinsCredentialsRule(this).withCredentials('test_cfCredentialsId', 'test_cf', '********'))
.around(jsr) // needs to be activated after jedr, otherwise executeDocker is not mocked
- @Before
- void init() throws Throwable {
- helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m })
- helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
- if(l[0].credentialsId == 'test_cfCredentialsId') {
- binding.setProperty('username', 'test_cf')
- binding.setProperty('password', '********')
- } else if(l[0].credentialsId == 'test_camCredentialsId') {
- binding.setProperty('username', 'test_cam')
- binding.setProperty('password', '********')
- }
- try {
- c()
- } finally {
- binding.setProperty('username', null)
- binding.setProperty('password', null)
- }
- })
- }
-
@Test
void testNoTool() throws Exception {
nullScript.commonPipelineEnvironment.configuration = [
diff --git a/test/groovy/NeoDeployTest.groovy b/test/groovy/NeoDeployTest.groovy
index a39f2a771..3e6841981 100644
--- a/test/groovy/NeoDeployTest.groovy
+++ b/test/groovy/NeoDeployTest.groovy
@@ -5,8 +5,10 @@ import org.junit.rules.TemporaryFolder
import org.junit.BeforeClass
import org.junit.ClassRule
import org.junit.Ignore
+
import org.hamcrest.BaseMatcher
import org.hamcrest.Description
+import org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
@@ -15,6 +17,7 @@ import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import util.BasePiperTest
+import util.JenkinsCredentialsRule
import util.JenkinsLoggingRule
import util.JenkinsReadYamlRule
import util.JenkinsShellCallRule
@@ -40,6 +43,9 @@ class NeoDeployTest extends BasePiperTest {
.around(thrown)
.around(jlr)
.around(jscr)
+ .around(new JenkinsCredentialsRule(this)
+ .withCredentials('myCredentialsId', 'anonymous', '********')
+ .withCredentials('CI_CREDENTIALS_ID', 'defaultUser', '********'))
.around(jsr)
private static workspacePath
@@ -66,24 +72,6 @@ class NeoDeployTest extends BasePiperTest {
helper.registerAllowedMethod('dockerExecute', [Map, Closure], null)
helper.registerAllowedMethod('fileExists', [String], { s -> return new File(workspacePath, s).exists() })
- helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m })
- helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
- if(l[0].credentialsId == 'myCredentialsId') {
- binding.setProperty('username', 'anonymous')
- binding.setProperty('password', '********')
- } else if(l[0].credentialsId == 'CI_CREDENTIALS_ID') {
- binding.setProperty('username', 'defaultUser')
- binding.setProperty('password', '********')
- }
- try {
- c()
- } finally {
- binding.setProperty('username', null)
- binding.setProperty('password', null)
- }
-
- })
-
helper.registerAllowedMethod('sh', [Map], { Map m -> getVersionWithEnvVars(m) })
nullScript.commonPipelineEnvironment.configuration = [steps:[neoDeploy: [host: 'test.deploy.host.com', account: 'trialuser123']]]
@@ -179,8 +167,7 @@ class NeoDeployTest extends BasePiperTest {
@Test
void badCredentialsIdTest() {
- thrown.expect(MissingPropertyException)
- thrown.expectMessage('No such property: username')
+ thrown.expect(CredentialNotFoundException)
jsr.step.call(script: nullScript,
archivePath: archiveName,
diff --git a/test/groovy/PrepareDefaultValuesTest.groovy b/test/groovy/PrepareDefaultValuesTest.groovy
index 3be4d5333..6d9195f48 100644
--- a/test/groovy/PrepareDefaultValuesTest.groovy
+++ b/test/groovy/PrepareDefaultValuesTest.groovy
@@ -30,16 +30,14 @@ public class PrepareDefaultValuesTest extends BasePiperTest {
@Before
public void setup() {
- helper.registerAllowedMethod("libraryResource", [String], { fileName-> return fileName })
- helper.registerAllowedMethod("readYaml", [Map], { m ->
- switch(m.text) {
- case 'default_pipeline_environment.yml': return [default: 'config']
- case 'custom.yml': return [custom: 'myConfig']
+ helper.registerAllowedMethod("libraryResource", [String], { fileName ->
+ switch(fileName) {
+ case 'default_pipeline_environment.yml': return "default: 'config'"
+ case 'custom.yml': return "custom: 'myConfig'"
case 'not_found': throw new hudson.AbortException('No such library resource not_found could be found')
- default: return [the:'end']
+ default: return "the:'end'"
}
})
-
}
@Test
@@ -54,11 +52,16 @@ public class PrepareDefaultValuesTest extends BasePiperTest {
@Test
public void testReInitializeOnCustomConfig() {
- DefaultValueCache.createInstance([key:'value'])
+ def instance = DefaultValueCache.createInstance([key:'value'])
// existing instance is dropped in case a custom config is provided.
jsr.step.call(script: nullScript, customDefaults: 'custom.yml')
+ // this check is for checking we have another instance
+ assert ! instance.is(DefaultValueCache.getInstance())
+
+ // some additional checks that the configuration represented by the new
+ // config is fine
assert DefaultValueCache.getInstance().getDefaultValues().size() == 2
assert DefaultValueCache.getInstance().getDefaultValues().default == 'config'
assert DefaultValueCache.getInstance().getDefaultValues().custom == 'myConfig'
@@ -67,10 +70,11 @@ public class PrepareDefaultValuesTest extends BasePiperTest {
@Test
public void testNoReInitializeWithoutCustomConfig() {
- DefaultValueCache.createInstance([key:'value'])
+ def instance = DefaultValueCache.createInstance([key:'value'])
jsr.step.call(script: nullScript)
+ assert instance.is(DefaultValueCache.getInstance())
assert DefaultValueCache.getInstance().getDefaultValues().size() == 1
assert DefaultValueCache.getInstance().getDefaultValues().key == 'value'
}
diff --git a/test/groovy/com/sap/piper/ConfigurationHelperTest.groovy b/test/groovy/com/sap/piper/ConfigurationHelperTest.groovy
index 4d82d55b0..634979743 100644
--- a/test/groovy/com/sap/piper/ConfigurationHelperTest.groovy
+++ b/test/groovy/com/sap/piper/ConfigurationHelperTest.groovy
@@ -279,4 +279,32 @@ class ConfigurationHelperTest {
Assert.assertThat(configuration, hasEntry('collectTelemetryData', false))
}
+
+ @Test
+ public void testGStringsAreReplacedByJavaLangStrings() {
+ //
+ // needed in order to ensure we have real GStrings.
+ // a GString not containing variables might be optimized to
+ // a java.lang.String from the very beginning.
+ def dummy = 'Dummy',
+ aGString = "a${dummy}",
+ bGString = "b${dummy}",
+ cGString = "c${dummy}"
+
+ assert aGString instanceof GString
+ assert bGString instanceof GString
+ assert cGString instanceof GString
+
+ def config = new ConfigurationHelper([a: aGString,
+ nextLevel: [b: bGString]])
+ .mixin([c : cGString])
+ .use()
+
+ assert config == [a: 'aDummy',
+ c: 'cDummy',
+ nextLevel: [b: 'bDummy']]
+ assert config.a instanceof java.lang.String
+ assert config.c instanceof java.lang.String
+ assert config.nextLevel.b instanceof java.lang.String
+ }
}
diff --git a/test/groovy/com/sap/piper/MapUtilsTest.groovy b/test/groovy/com/sap/piper/MapUtilsTest.groovy
index 2d38e9f0f..61a06aaf8 100644
--- a/test/groovy/com/sap/piper/MapUtilsTest.groovy
+++ b/test/groovy/com/sap/piper/MapUtilsTest.groovy
@@ -43,4 +43,11 @@ class MapUtilsTest {
c: [ d: 'abc',
e: '']]
}
+
+ @Test
+ void testTraverse() {
+ Map m = [a: 'x1', m:[b: 'x2', c: 'otherString']]
+ MapUtils.traverse(m, { s -> (s.startsWith('x')) ? "replaced" : s})
+ assert m == [a: 'replaced', m: [b: 'replaced', c: 'otherString']]
+ }
}
diff --git a/test/groovy/util/JenkinsCredentialsRule.groovy b/test/groovy/util/JenkinsCredentialsRule.groovy
index 63133c372..5f6e7dd8c 100644
--- a/test/groovy/util/JenkinsCredentialsRule.groovy
+++ b/test/groovy/util/JenkinsCredentialsRule.groovy
@@ -14,6 +14,7 @@ import static org.hamcrest.Matchers.nullValue
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers
+import org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException
/**
* By default a user "anonymous" with password "********"
@@ -47,16 +48,19 @@ class JenkinsCredentialsRule implements TestRule {
@Override
void evaluate() throws Throwable {
- testInstance.helper.registerAllowedMethod('usernamePassword', [Map.class], {m -> return m})
+ testInstance.helper.registerAllowedMethod('usernamePassword', [Map.class],
+ { m -> if (credentials.keySet().contains(m.credentialsId)) return m;
+ // this is what really happens in case of an unknown credentials id,
+ // checked with reality using credentials plugin 2.1.18.
+ throw new CredentialNotFoundException(
+ "Could not find credentials entry with ID '${m.credentialsId}'")
+ })
testInstance.helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
def credsId = l[0].credentialsId
def creds = credentials.get(credsId)
- assertThat("Unexpected credentialsId received: '${credsId}'.",
- creds, is(not(nullValue())))
-
binding.setProperty('username', creds?.user)
binding.setProperty('password', creds?.passwd)
try {