github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/test/groovy/XsDeployTest.groovy (about) 1 import com.sap.piper.DefaultValueCache 2 import static org.hamcrest.Matchers.allOf 3 import static org.hamcrest.Matchers.contains 4 import static org.hamcrest.Matchers.containsInAnyOrder 5 import static org.hamcrest.Matchers.containsString 6 import static org.hamcrest.Matchers.equalTo 7 import static org.hamcrest.Matchers.is 8 import static org.hamcrest.Matchers.not 9 import static org.hamcrest.Matchers.nullValue 10 import static org.junit.Assert.assertThat 11 12 import org.hamcrest.Matchers 13 import org.hamcrest.core.IsNull 14 import org.junit.After 15 import org.junit.Before 16 import org.junit.Rule 17 import org.junit.Test 18 import org.junit.rules.ExpectedException 19 import org.junit.rules.RuleChain 20 21 import com.sap.piper.PiperGoUtils 22 import com.sap.piper.Utils 23 24 import hudson.AbortException 25 import util.BasePiperTest 26 import util.CommandLineMatcher 27 import util.JenkinsCredentialsRule 28 import util.JenkinsDockerExecuteRule 29 import util.JenkinsLockRule 30 import util.JenkinsReadJsonRule 31 import util.JenkinsReadYamlRule 32 import util.JenkinsShellCallRule 33 import util.JenkinsStepRule 34 import util.JenkinsWriteFileRule 35 import util.Rules 36 37 class XsDeployTest extends BasePiperTest { 38 39 private ExpectedException thrown = ExpectedException.none() 40 41 private JenkinsStepRule stepRule = new JenkinsStepRule(this) 42 private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this) 43 private JenkinsLockRule lockRule = new JenkinsLockRule(this) 44 private JenkinsDockerExecuteRule dockerRule = new JenkinsDockerExecuteRule(this) 45 private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this) 46 47 List env 48 49 @Rule 50 public RuleChain ruleChain = Rules.getCommonRules(this) 51 .around(new JenkinsReadYamlRule(this)) 52 .around(new JenkinsReadJsonRule(this)) 53 .around(stepRule) 54 .around(dockerRule) 55 .around(writeFileRule) 56 .around(new JenkinsCredentialsRule(this) 57 .withCredentials('myCreds', 'cred_xs', 'topSecret')) 58 .around(lockRule) 59 .around(shellRule) 60 .around(thrown) 61 62 private PiperGoUtils goUtils = new PiperGoUtils(null) { 63 void unstashPiperBin() { 64 } 65 } 66 67 @Before 68 public void init() { 69 helper.registerAllowedMethod('withEnv', [List, Closure], {l, c -> env = l; c()}) 70 71 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig.*--contextConfig.*', '{"dockerImage": "xs", "dockerPullImage": false, "credentialsId":"myCreds"}') 72 73 // what we set on the shell rule and on the null script is the same. We read it on the groovy level, and also via go getConfig, hence we need it twice. 74 nullScript.commonPipelineEnvironment.configuration = [steps: [xsDeploy: [mode: 'BG_DEPLOY', action: 'NONE', apiUrl: 'https://example.org/xs', org: 'myOrg', space: 'mySpace']]] 75 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}') 76 77 nullScript.commonPipelineEnvironment.xsDeploymentId = null 78 79 Utils.metaClass.echo = { def m -> } 80 } 81 82 @After 83 public void tearDown() { 84 Utils.metaClass = null 85 } 86 87 @Test 88 public void testDeployFailed() { 89 90 thrown.expect(AbortException) 91 thrown.expectMessage('script returned exit code 1') 92 93 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', { throw new AbortException('script returned exit code 1')}) 94 95 stepRule.step.xsDeploy( 96 script: nullScript, 97 piperGoUtils: goUtils, 98 ) 99 } 100 101 @Test 102 public void testInvalidDeploymentModeProvided() { 103 104 thrown.expect(IllegalArgumentException) 105 thrown.expectMessage('No enum constant') 106 107 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "DOES_NOT_EXIST", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}') 108 nullScript.commonPipelineEnvironment.configuration = [steps: [xsDeploy: [mode: 'DOES_NOT_EXIST', action: 'NONE', apiUrl: 'https://example.org/xs', org: 'myOrg', space: 'mySpace']]] 109 110 stepRule.step.xsDeploy( 111 script: nullScript, 112 piperGoUtils: goUtils, 113 ) 114 } 115 116 @Test 117 public void testDeployableViaCPE() { 118 119 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', ' ') 120 121 nullScript.commonPipelineEnvironment.mtarFilePath = "my.mtar" 122 123 stepRule.step.xsDeploy( 124 script: nullScript, 125 apiUrl: 'https://example.org/xs', 126 org: 'myOrg', 127 space: 'mySpace', 128 credentialsId: 'myCreds', 129 deployOpts: '-t 60', 130 mtaPath: 'myApp.mta', 131 mode: 'DEPLOY', 132 action: 'NONE', 133 piperGoUtils: goUtils 134 ) 135 136 assertThat(shellRule.shell, 137 new CommandLineMatcher() 138 .hasProlog('#!/bin/bash ./piper xsDeploy') 139 // explicitly provided, it is not contained in project config. 140 .hasOption('mtaPath', 'my.mtar')) 141 } 142 143 @Test 144 public void testParametersViaSignature() { 145 146 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', '{"operationId": "1234"}') 147 148 stepRule.step.xsDeploy( 149 script: nullScript, 150 apiUrl: 'https://example.org/xs', 151 org: 'myOrg', 152 space: 'mySpace', 153 credentialsId: 'myCreds', 154 deployOpts: '-t 60', 155 mtaPath: 'myApp.mta', 156 mode: 'DEPLOY', 157 action: 'NONE', 158 piperGoUtils: goUtils 159 ) 160 161 // nota bene: script and piperGoUtils are not contained in the json below. 162 assertThat(env*.toString(), contains('PIPER_parametersJSON={"apiUrl":"https://example.org/xs","org":"myOrg","space":"mySpace","credentialsId":"myCreds","deployOpts":"-t 60","mtaPath":"myApp.mta","mode":"DEPLOY","action":"NONE"}')) 163 } 164 165 @Test 166 public void testBlueGreenDeployInit() { 167 168 // 169 // Only difference between bg deploy and standard deploy is in the config. 170 // The surrounding behavior is the same. Hence there is no dedicated test here 171 // in the groovy layer for standard deploy 172 // 173 174 boolean unstashCalled 175 176 assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue()) 177 178 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', '{"operationId": "1234"}') 179 180 goUtils = new PiperGoUtils(null) { 181 void unstashPiperBin() { 182 unstashCalled = true 183 } 184 } 185 stepRule.step.xsDeploy( 186 script: nullScript, 187 piperGoUtils: goUtils 188 ) 189 190 assertThat(unstashCalled, equalTo(true)) 191 192 assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, is('1234')) 193 194 assertThat(writeFileRule.files.keySet(), containsInAnyOrder( 195 '.pipeline/additionalConfigs/default_pipeline_environment.yml', 196 '.pipeline/metadata/xsDeploy.yaml', 197 )) 198 199 assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs')) 200 assertThat(dockerRule.dockerParams.dockerPullImage, equalTo(false)) 201 202 assertThat(shellRule.shell, 203 allOf( 204 new CommandLineMatcher() 205 .hasProlog('./piper version'), 206 new CommandLineMatcher() 207 .hasProlog('./piper getConfig') 208 .hasArgument('--contextConfig'), 209 new CommandLineMatcher() 210 .hasProlog('./piper getConfig --stepMetadata \'.pipeline/metadata/xsDeploy.yaml\''), 211 new CommandLineMatcher() 212 .hasProlog('#!/bin/bash ./piper xsDeploy --defaultConfig ".pipeline/additionalConfigs/default_pipeline_environment.yml" --username \\$\\{USERNAME\\} --password \\$\\{PASSWORD\\}'), 213 not(new CommandLineMatcher() 214 .hasProlog('#!/bin/bash ./piper xsDeploy') 215 .hasOption('operationId', '1234')) 216 ) 217 ) 218 219 assertThat(lockRule.getLockResources(), contains('xsDeploy:https://example.org/xs:myOrg:mySpace')) 220 } 221 222 @Test 223 public void testBlueGreenDeployResume() { 224 225 nullScript.commonPipelineEnvironment.xsDeploymentId = '1234' 226 227 nullScript.commonPipelineEnvironment.configuration = [steps: [xsDeploy: [mode: 'BG_DEPLOY', action: 'RESUME', apiUrl: 'https://example.org/xs', org: 'myOrg', space: 'mySpace']]] 228 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}') 229 230 stepRule.step.xsDeploy( 231 script: nullScript, 232 piperGoUtils: goUtils 233 ) 234 235 assertThat(shellRule.shell, 236 new CommandLineMatcher() 237 .hasProlog('#!/bin/bash ./piper xsDeploy') 238 .hasOption('operationId', '1234') 239 ) 240 241 assertThat(lockRule.getLockResources(), contains('xsDeploy:https://example.org/xs:myOrg:mySpace')) 242 } 243 244 @Test 245 public void testBlueGreenDeployResumeWithoutDeploymentId() { 246 247 // this happens in case we would like to complete a deployment without having a (successful) deployments before. 248 249 thrown.expect(IllegalArgumentException) 250 thrown.expectMessage( 251 allOf( 252 containsString('No operationId provided'), 253 containsString('Was there a deployment before?'))) 254 255 nullScript.commonPipelineEnvironment.configuration = [steps: [xsDeploy: [mode: 'BG_DEPLOY', action: 'RESUME', apiUrl: 'https://example.org/xs', org: 'myOrg', space: 'mySpace']]] 256 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}') 257 258 assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue()) 259 260 stepRule.step.xsDeploy( 261 script: nullScript, 262 piperGoUtils: goUtils, 263 failOnError: true, 264 ) 265 } 266 267 @Test 268 public void testBlueGreenDeployResumeOperationIdViaSignature() { 269 270 // this happens in case we would like to complete a deployment without having a (successful) deployments before. 271 272 nullScript.commonPipelineEnvironment.configuration = [steps: [xsDeploy: [mode: 'BG_DEPLOY', action: 'RESUME', apiUrl: 'https://example.org/xs', org: 'myOrg', space: 'mySpace']]] 273 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}') 274 275 assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue()) 276 277 stepRule.step.xsDeploy( 278 script: nullScript, 279 piperGoUtils: goUtils, 280 failOnError: true, 281 operationId: '1357' 282 ) 283 284 assertThat(shellRule.shell, 285 new CommandLineMatcher() 286 .hasProlog('#!/bin/bash ./piper xsDeploy') 287 .hasOption('operationId', '1357') 288 ) 289 } 290 291 @Test 292 public void testDockerParamsViaProjectConfig() { 293 294 295 nullScript.commonPipelineEnvironment.configuration = [steps: 296 [xsDeploy: 297 [ 298 dockerImage: 'xs1', 299 dockerPullImage: true 300 ] 301 ] 302 ] 303 304 stepRule.step.xsDeploy( 305 script: nullScript, 306 piperGoUtils: goUtils 307 ) 308 309 // 'xs' provided on the context config is superseded by the value set in the project 310 assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs1')) 311 assertThat(dockerRule.dockerParams.dockerPullImage, equalTo(true)) 312 } 313 314 @Test 315 public void testDockerParamsViaProjectConfigNested() { 316 317 318 nullScript.commonPipelineEnvironment.configuration = [steps: 319 [xsDeploy: 320 [ 321 docker: [ 322 dockerImage: 'xs1', 323 dockerPullImage: true 324 ] 325 ] 326 ] 327 ] 328 329 stepRule.step.xsDeploy( 330 script: nullScript, 331 piperGoUtils: goUtils 332 ) 333 334 // 'xs' provided on the context config is superseded by the value set in the project 335 assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs1')) 336 assertThat(dockerRule.dockerParams.dockerPullImage, equalTo(true)) 337 } 338 339 @Test 340 public void testDockerParamsViaSignature() { 341 342 343 nullScript.commonPipelineEnvironment.configuration = [steps: 344 [xsDeploy: 345 [ 346 dockerImage: 'xs1' 347 ] 348 ] 349 ] 350 351 stepRule.step.xsDeploy( 352 script: nullScript, 353 piperGoUtils: goUtils, 354 dockerImage: 'xs2', 355 ) 356 357 // 'xs' provided on the context config and 'xs1' provided by project config 358 // is superseded by the value set in the project 359 assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs2')) 360 } 361 362 @Test 363 public void testAdditionalCustomConfigLayers() { 364 365 def resources = ['a.yml': '- x: y}', 'b.yml' : '- a: b}'] 366 367 helper.registerAllowedMethod('libraryResource', [String], { 368 369 r -> 370 371 def resource = resources[r] 372 if(resource) return resource 373 374 File res = new File(new File('resources'), r) 375 if (res.exists()) { 376 return res.getText() 377 } 378 379 throw new RuntimeException("Resource '${r}' not found.") 380 }) 381 382 assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue()) 383 384 shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', '{"operationId": "1234"}') 385 386 DefaultValueCache.createInstance([:], ['a.yml', 'b.yml']) 387 388 goUtils = new PiperGoUtils(null) { 389 void unstashPiperBin() { 390 } 391 } 392 stepRule.step.xsDeploy( 393 script: nullScript, 394 piperGoUtils: goUtils 395 ) 396 397 assertThat(writeFileRule.files.keySet(), containsInAnyOrder( 398 '.pipeline/additionalConfigs/a.yml', 399 '.pipeline/additionalConfigs/b.yml', 400 '.pipeline/additionalConfigs/default_pipeline_environment.yml', 401 '.pipeline/metadata/xsDeploy.yaml', 402 )) 403 404 assertThat(shellRule.shell, 405 allOf( 406 new CommandLineMatcher() 407 .hasProlog('./piper getConfig') 408 .hasArgument('--contextConfig') 409 .hasArgument('--defaultConfig ".pipeline/additionalConfigs/b.yml" ".pipeline/additionalConfigs/a.yml" ".pipeline/additionalConfigs/default_pipeline_environment.yml"'), 410 new CommandLineMatcher() 411 .hasProlog('./piper getConfig --stepMetadata \'.pipeline/metadata/xsDeploy.yaml\''), 412 ) 413 ) 414 } 415 }