github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/test/groovy/SetupCommonPipelineEnvironmentTest.groovy (about) 1 import com.sap.piper.DefaultValueCache 2 import com.sap.piper.Utils 3 import com.sap.piper.GitUtils 4 import org.junit.After 5 import org.junit.Before 6 import org.junit.Rule 7 import org.junit.Test 8 import org.junit.rules.ExpectedException 9 import org.junit.rules.RuleChain 10 import org.yaml.snakeyaml.Yaml 11 import util.BasePiperTest 12 import util.JenkinsLoggingRule 13 import util.JenkinsReadFileRule 14 import util.JenkinsShellCallRule 15 import util.JenkinsStepRule 16 import util.JenkinsWriteFileRule 17 import util.Rules 18 19 import static org.hamcrest.Matchers.is 20 import static org.junit.Assert.assertEquals 21 import static org.junit.Assert.assertNotNull 22 import static org.junit.Assert.assertNull 23 import static org.junit.Assert.assertThat 24 25 class SetupCommonPipelineEnvironmentTest extends BasePiperTest { 26 27 def usedConfigFile 28 def pipelineAndTestStashIncludes 29 def utilsMock 30 31 private JenkinsStepRule stepRule = new JenkinsStepRule(this) 32 private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this) 33 private ExpectedException thrown = ExpectedException.none() 34 private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this) 35 private JenkinsReadFileRule readFileRule = new JenkinsReadFileRule(this, "./") 36 private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this) 37 38 @Rule 39 public RuleChain rules = Rules 40 .getCommonRules(this) 41 .around(stepRule) 42 .around(writeFileRule) 43 .around(thrown) 44 .around(shellRule) 45 .around(readFileRule) 46 .around(loggingRule) 47 48 @Before 49 void init() { 50 51 def examplePipelineConfig = new File('test/resources/test_pipeline_config.yml').text 52 53 helper.registerAllowedMethod("libraryResource", [String], { fileName -> 54 switch(fileName) { 55 case 'default_pipeline_environment.yml': return "default: 'config'" 56 case 'custom.yml': return "custom: 'myConfig'" 57 case 'notFound.yml': throw new hudson.AbortException('No such library resource notFound could be found') 58 default: return "the:'end'" 59 } 60 }) 61 62 helper.registerAllowedMethod("readYaml", [Map], { Map parameters -> 63 Yaml yamlParser = new Yaml() 64 if (parameters.text) { 65 return yamlParser.load(parameters.text) 66 } else if (parameters.file) { 67 switch (parameters.file) { 68 case '.pipeline/default_pipeline_environment.yml': 69 return [default: 'config'] 70 case '.pipeline/custom.yml': 71 return [custom: 'myConfig'] 72 case 'pipeline_config.yml': 73 usedConfigFile = parameters.file 74 return [ 75 general: [ 76 productiveBranch: 'main' 77 ], 78 steps: [ 79 mavenExecute: [ 80 dockerImage: 'my-custom-maven-docker'] 81 ] 82 ] 83 } 84 } else { 85 throw new IllegalArgumentException("Key 'text' and 'file' are both missing in map ${m}.") 86 } 87 usedConfigFile = parameters.file 88 return yamlParser.load(examplePipelineConfig) 89 }) 90 utilsMock = newUtilsMock() 91 } 92 93 Utils newUtilsMock() { 94 def utilsMock = new Utils() 95 utilsMock.steps = [ 96 stash : { Map params -> pipelineAndTestStashIncludes = params.includes }, 97 unstash: { } 98 ] 99 utilsMock.echo = { def m -> } 100 return utilsMock 101 } 102 103 @Test 104 void testIsYamlConfigurationAvailable() throws Exception { 105 106 helper.registerAllowedMethod("fileExists", [String], { String path -> 107 return path.endsWith('.pipeline/config.yml') 108 }) 109 110 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock) 111 112 assertEquals('.pipeline/config.yml', usedConfigFile) 113 assertNotNull(nullScript.commonPipelineEnvironment.configuration) 114 assertEquals('develop', nullScript.commonPipelineEnvironment.configuration.general.productiveBranch) 115 assertEquals('my-maven-docker', nullScript.commonPipelineEnvironment.configuration.steps.mavenExecute.dockerImage) 116 assertEquals('.pipeline/**', pipelineAndTestStashIncludes) 117 } 118 119 @Test 120 void testWorksAlsoWithYamlFileEnding() throws Exception { 121 122 helper.registerAllowedMethod("fileExists", [String], { String path -> 123 return path.endsWith('.pipeline/config.yaml') 124 }) 125 126 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock) 127 128 assertEquals('.pipeline/config.yaml', usedConfigFile) 129 assertNotNull(nullScript.commonPipelineEnvironment.configuration) 130 assertEquals('develop', nullScript.commonPipelineEnvironment.configuration.general.productiveBranch) 131 assertEquals('my-maven-docker', nullScript.commonPipelineEnvironment.configuration.steps.mavenExecute.dockerImage) 132 assertEquals('.pipeline/**', pipelineAndTestStashIncludes) 133 } 134 135 @Test 136 void testWorksAlsoWithCustomConfig() throws Exception { 137 138 helper.registerAllowedMethod("fileExists", [String], { String path -> 139 return path.endsWith('pipeline_config.yml') 140 }) 141 142 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, configFile: 'pipeline_config.yml') 143 144 assertEquals('pipeline_config.yml', usedConfigFile) 145 assertNotNull(nullScript.commonPipelineEnvironment.configuration) 146 assertEquals('main', nullScript.commonPipelineEnvironment.configuration.general.productiveBranch) 147 assertEquals('my-custom-maven-docker', nullScript.commonPipelineEnvironment.configuration.steps.mavenExecute.dockerImage) 148 assertEquals('.pipeline/**, pipeline_config.yml', pipelineAndTestStashIncludes) 149 } 150 151 @Test 152 void testAttemptToLoadNonExistingConfigFile() { 153 154 helper.registerAllowedMethod("fileExists", [String], { String path -> 155 switch(path) { 156 case 'default_pipeline_environment.yml': return false 157 case 'custom.yml': return false 158 case 'notFound.yml': return false 159 case '': throw new RuntimeException('cannot call fileExists with empty path') 160 default: return true 161 } 162 }) 163 164 helper.registerAllowedMethod("handlePipelineStepErrors", [Map,Closure], { Map map, Closure closure -> 165 closure() 166 }) 167 168 // Behavior documented here based on reality check 169 thrown.expect(hudson.AbortException.class) 170 thrown.expectMessage('No such library resource notFound could be found') 171 172 stepRule.step.setupCommonPipelineEnvironment( 173 script: nullScript, 174 utils: utilsMock, 175 customDefaults: 'notFound.yml' 176 ) 177 } 178 179 @Test 180 void testInvalidEntriesInCustomDefaults() { 181 182 helper.registerAllowedMethod("fileExists", [String], { String path -> 183 switch(path) { 184 case 'default_pipeline_environment.yml': return false 185 case '': throw new RuntimeException('cannot call fileExists with empty path') 186 default: return true 187 } 188 }) 189 190 helper.registerAllowedMethod("handlePipelineStepErrors", [Map,Closure], { Map map, Closure closure -> 191 closure() 192 }) 193 194 helper.registerAllowedMethod("readYaml", [Map], { Map parameters -> 195 Yaml yamlParser = new Yaml() 196 if (parameters.text) { 197 return yamlParser.load(parameters.text) 198 } else if (parameters.file) { 199 if (parameters.file == '.pipeline/config-with-custom-defaults.yml') { 200 return [customDefaults: ['', true]] 201 } 202 } 203 throw new IllegalArgumentException("Unexpected invocation of readYaml step") 204 }) 205 206 stepRule.step.setupCommonPipelineEnvironment( 207 script: nullScript, 208 utils: utilsMock, 209 configFile: '.pipeline/config-with-custom-defaults.yml' 210 ) 211 212 assertEquals('WARNING: Ignoring invalid entry in custom defaults from files: \'\' \n' + 213 'WARNING: Ignoring invalid entry in custom defaults from files: \'true\' \n', loggingRule.getLog()) 214 } 215 216 @Test 217 void testAttemptToLoadFileFromURL() { 218 helper.registerAllowedMethod("fileExists", [String], {String path -> 219 switch (path) { 220 case 'default_pipeline_environment.yml': return false 221 case '': throw new RuntimeException('cannot call fileExists with empty path') 222 default: return true 223 } 224 }) 225 226 String customDefaultUrl = "https://url-to-my-config.com/my-config.yml" 227 boolean urlRequested = false 228 229 helper.registerAllowedMethod("httpRequest", [Map], {Map parameters -> 230 switch (parameters.url) { 231 case customDefaultUrl: 232 urlRequested = true 233 return [status: 200, content: "custom: 'myRemoteConfig'"] 234 default: 235 throw new IllegalArgumentException('wrong URL requested') 236 } 237 }) 238 239 helper.registerAllowedMethod("readYaml", [Map], { Map parameters -> 240 Yaml yamlParser = new Yaml() 241 if (parameters.text) { 242 return yamlParser.load(parameters.text) 243 } else if (parameters.file) { 244 if (parameters.file == '.pipeline/config-with-custom-defaults.yml') { 245 return [customDefaults: "${customDefaultUrl}"] 246 } 247 if (parameters.file == '.pipeline/custom_default_from_url_0.yml') { 248 return [custom: 'myRemoteConfig'] 249 } 250 } 251 throw new IllegalArgumentException("Unexpected invocation of readYaml step") 252 }) 253 254 stepRule.step.setupCommonPipelineEnvironment( 255 script: nullScript, 256 utils: utilsMock, 257 customDefaults: 'custom.yml', 258 configFile: '.pipeline/config-with-custom-defaults.yml', 259 ) 260 assertEquals("custom: 'myRemoteConfig'", writeFileRule.files['.pipeline/custom_default_from_url_0.yml']) 261 assertEquals('myRemoteConfig', DefaultValueCache.instance.defaultValues['custom']) 262 } 263 264 265 @Test 266 void inferBuildToolMaven() { 267 helper.registerAllowedMethod('fileExists', [String.class], { s -> 268 return s == "pom.xml" 269 }) 270 setupCommonPipelineEnvironment.inferBuildTool(nullScript, [inferBuildTool: true]) 271 assertEquals('maven', nullScript.commonPipelineEnvironment.buildTool) 272 } 273 274 @Test 275 void inferBuildToolMTA() { 276 helper.registerAllowedMethod('fileExists', [String.class], { s -> 277 return s == "mta.yaml" 278 }) 279 setupCommonPipelineEnvironment.inferBuildTool(nullScript, [inferBuildTool: true]) 280 assertEquals('mta', nullScript.commonPipelineEnvironment.buildTool) 281 } 282 283 @Test 284 void inferBuildToolNpm() { 285 helper.registerAllowedMethod('fileExists', [String.class], { s -> 286 return s == "package.json" 287 }) 288 setupCommonPipelineEnvironment.inferBuildTool(nullScript, [inferBuildTool: true]) 289 assertEquals('npm', nullScript.commonPipelineEnvironment.buildTool) 290 } 291 292 @Test 293 void inferBuildToolNone() { 294 helper.registerAllowedMethod('fileExists', [String.class], { s -> 295 return false 296 }) 297 setupCommonPipelineEnvironment.inferBuildTool(nullScript, [inferBuildTool: true]) 298 assertNull(nullScript.commonPipelineEnvironment.buildTool) 299 } 300 301 @Test 302 void "Set scmInfo parameter sets commit id"() { 303 304 def GitUtils gitUtils = new GitUtils() { 305 boolean isMergeCommit(){ 306 return false 307 } 308 } 309 310 helper.registerAllowedMethod("fileExists", [String], { String path -> 311 return path.endsWith('.pipeline/config.yml') 312 }) 313 314 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_URL: 'https://github.com/testOrg/testRepo.git'] 315 316 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 317 assertThat(nullScript.commonPipelineEnvironment.gitCommitId, is('dummy_git_commit_id')) 318 } 319 320 @Test 321 void "Set scmInfo parameter sets git reference for branch"() { 322 323 def GitUtils gitUtils = new GitUtils() { 324 boolean isMergeCommit(){ 325 return false 326 } 327 } 328 329 helper.registerAllowedMethod("fileExists", [String], { String path -> 330 return path.endsWith('.pipeline/config.yml') 331 }) 332 333 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'origin/testbranch'] 334 335 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 336 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/heads/testbranch')) 337 } 338 339 @Test 340 void "Set scmInfo parameter sets git reference for branch with slashes in name, origin"() { 341 342 def GitUtils gitUtils = new GitUtils() { 343 boolean isMergeCommit(){ 344 return false 345 } 346 } 347 348 helper.registerAllowedMethod("fileExists", [String], { String path -> 349 return path.endsWith('.pipeline/config.yml') 350 }) 351 352 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'origin/testbranch/001'] 353 354 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 355 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/heads/testbranch/001')) 356 } 357 358 @Test 359 void "Set scmInfo parameter sets git reference for branch with slashes in name, not origin"() { 360 361 def GitUtils gitUtils = new GitUtils() { 362 boolean isMergeCommit(){ 363 return false 364 } 365 } 366 367 helper.registerAllowedMethod("fileExists", [String], { String path -> 368 return path.endsWith('.pipeline/config.yml') 369 }) 370 371 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'testbranch/001'] 372 373 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 374 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/heads/testbranch/001')) 375 } 376 377 @Test 378 void "sets gitReference and gitRemoteCommit for pull request, head strategy"() { 379 380 def GitUtils gitUtils = new GitUtils() { 381 boolean isMergeCommit(){ 382 return false 383 } 384 385 String getMergeCommitSha(){ 386 return "dummy_merge_git_commit_id" 387 } 388 } 389 390 helper.registerAllowedMethod("fileExists", [String], { String path -> 391 return path.endsWith('.pipeline/config.yml') 392 }) 393 394 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42'] 395 396 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 397 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/head')) 398 assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('dummy_git_commit_id')) 399 } 400 401 @Test 402 void "sets gitReference and gitRemoteCommit for pull request, merge strategy"() { 403 404 def GitUtils gitUtils = new GitUtils() { 405 boolean isMergeCommit(){ 406 return true 407 } 408 409 String getMergeCommitSha(){ 410 return "dummy_merge_git_commit_id" 411 } 412 } 413 414 helper.registerAllowedMethod("fileExists", [String], { String path -> 415 return path.endsWith('.pipeline/config.yml') 416 }) 417 418 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42'] 419 420 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 421 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/merge')) 422 assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('dummy_merge_git_commit_id')) 423 } 424 425 @Test 426 void "Set merge commit id as NA on exception"() { 427 428 def GitUtils gitUtils = new GitUtils() { 429 boolean isMergeCommit(){ 430 return true 431 } 432 433 String getMergeCommitSha() throws MissingPropertyException{ 434 throw new MissingPropertyException('pullRequest Context not found') 435 } 436 } 437 438 helper.registerAllowedMethod("fileExists", [String], { String path -> 439 return path.endsWith('.pipeline/config.yml') 440 }) 441 442 def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42'] 443 444 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock, scmInfo: dummyScmInfo, gitUtils: gitUtils) 445 assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/merge')) 446 assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('NA')) 447 } 448 449 @Test 450 void "No scmInfo passed as parameter yields empty git info"() { 451 helper.registerAllowedMethod("fileExists", [String], { String path -> 452 return path.endsWith('.pipeline/config.yml') 453 }) 454 455 stepRule.step.setupCommonPipelineEnvironment(script: nullScript, utils: utilsMock) 456 assertNull(nullScript.commonPipelineEnvironment.gitCommitId) 457 assertNull(nullScript.commonPipelineEnvironment.getGitSshUrl()) 458 assertNull(nullScript.commonPipelineEnvironment.getGitHttpsUrl()) 459 assertNull(nullScript.commonPipelineEnvironment.getGithubOrg()) 460 assertNull(nullScript.commonPipelineEnvironment.getGithubRepo()) 461 assertNull(nullScript.commonPipelineEnvironment.getGitRef()) 462 } 463 464 @Test 465 void testSetScmInfoOnCommonPipelineEnvironment() { 466 //currently supported formats 467 def scmInfoTestList = [ 468 [GIT_URL: 'https://github.com/testOrg/testRepo.git', expectedSsh: 'git@github.com:testOrg/testRepo.git', expectedHttp: 'https://github.com/testOrg/testRepo.git', expectedOrg: 'testOrg', expectedRepo: 'testRepo'], 469 [GIT_URL: 'https://github.com:7777/testOrg/testRepo.git', expectedSsh: 'git@github.com:testOrg/testRepo.git', expectedHttp: 'https://github.com:7777/testOrg/testRepo.git', expectedOrg: 'testOrg', expectedRepo: 'testRepo'], 470 [GIT_URL: 'git@github.com:testOrg/testRepo.git', expectedSsh: 'git@github.com:testOrg/testRepo.git', expectedHttp: 'https://github.com/testOrg/testRepo.git', expectedOrg: 'testOrg', expectedRepo: 'testRepo'], 471 [GIT_URL: 'ssh://git@github.com/testOrg/testRepo.git', expectedSsh: 'ssh://git@github.com/testOrg/testRepo.git', expectedHttp: 'https://github.com/testOrg/testRepo.git', expectedOrg: 'testOrg', expectedRepo: 'testRepo'], 472 [GIT_URL: 'ssh://git@github.com:7777/testOrg/testRepo.git', expectedSsh: 'ssh://git@github.com:7777/testOrg/testRepo.git', expectedHttp: 'https://github.com/testOrg/testRepo.git', expectedOrg: 'testOrg', expectedRepo: 'testRepo'], 473 [GIT_URL: 'ssh://git@github.com/path/to/testOrg/testRepo.git', expectedSsh: 'ssh://git@github.com/path/to/testOrg/testRepo.git', expectedHttp: 'https://github.com/path/to/testOrg/testRepo.git', expectedOrg: 'path/to/testOrg', expectedRepo: 'testRepo'], 474 [GIT_URL: 'ssh://git@github.com/path/testOrg/testRepo.git', expectedSsh: 'ssh://git@github.com/path/testOrg/testRepo.git', expectedHttp: 'https://github.com/path/testOrg/testRepo.git', expectedOrg: 'path/testOrg', expectedRepo: 'testRepo'], 475 [GIT_URL: 'ssh://git@github.com/testRepo.git', expectedSsh: 'ssh://git@github.com/testRepo.git', expectedHttp: 'https://github.com/testRepo.git', expectedOrg: 'N/A', expectedRepo: 'testRepo'], 476 ] 477 478 scmInfoTestList.each {scmInfoTest -> 479 stepRule.step.setupCommonPipelineEnvironment.setGitUrlsOnCommonPipelineEnvironment(nullScript, scmInfoTest.GIT_URL) 480 assertThat(nullScript.commonPipelineEnvironment.getGitSshUrl(), is(scmInfoTest.expectedSsh)) 481 assertThat(nullScript.commonPipelineEnvironment.getGitHttpsUrl(), is(scmInfoTest.expectedHttp)) 482 assertThat(nullScript.commonPipelineEnvironment.getGithubOrg(), is(scmInfoTest.expectedOrg)) 483 assertThat(nullScript.commonPipelineEnvironment.getGithubRepo(), is(scmInfoTest.expectedRepo)) 484 } 485 } 486 }