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  }