github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/test/groovy/PiperExecuteBinTest.groovy (about)

     1  import com.sap.piper.DebugReport
     2  import com.sap.piper.DefaultValueCache
     3  import com.sap.piper.JenkinsUtils
     4  import groovy.json.JsonSlurper
     5  import hudson.AbortException
     6  import org.junit.After
     7  import org.junit.Before
     8  import org.junit.Rule
     9  import org.junit.Test
    10  import org.junit.rules.ExpectedException
    11  import org.junit.rules.RuleChain
    12  import util.*
    13  
    14  import static org.hamcrest.Matchers.*
    15  import static org.junit.Assert.assertThat
    16  
    17  class PiperExecuteBinTest extends BasePiperTest {
    18      private ExpectedException exception = ExpectedException.none()
    19  
    20      private JenkinsCredentialsRule credentialsRule = new JenkinsCredentialsRule(this)
    21      private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
    22      private JenkinsStepRule stepRule = new JenkinsStepRule(this)
    23      private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this)
    24      private JenkinsFileExistsRule fileExistsRule = new JenkinsFileExistsRule(this, [])
    25      private JenkinsDockerExecuteRule dockerExecuteRule = new JenkinsDockerExecuteRule(this)
    26  
    27      private List withEnvArgs = []
    28      private List credentials = []
    29      private List artifacts = []
    30  
    31      @Rule
    32      public RuleChain rules = Rules
    33          .getCommonRules(this)
    34          .around(exception)
    35          .around(new JenkinsReadYamlRule(this))
    36          .around(credentialsRule)
    37          .around(shellCallRule)
    38          .around(stepRule)
    39          .around(writeFileRule)
    40          .around(fileExistsRule)
    41          .around(dockerExecuteRule)
    42  
    43      @Before
    44      void init() {
    45          credentials = []
    46  
    47          // Clear DebugReport to avoid left-overs from another UnitTest
    48          DebugReport.instance.failedBuild = [:]
    49  
    50          helper.registerAllowedMethod("withEnv", [List.class, Closure.class], {arguments, closure ->
    51              arguments.each {arg ->
    52                  withEnvArgs.add(arg.toString())
    53              }
    54              return closure()
    55          })
    56  
    57          helper.registerAllowedMethod("writePipelineEnv", [Map.class], {m -> return })
    58          helper.registerAllowedMethod("readPipelineEnv", [Map.class], {m -> return })
    59          helper.registerAllowedMethod('fileExists', [Map.class], {m ->
    60              if (m.file == 'noDetailsStep_errorDetails.json') {
    61                  return false
    62              }
    63              return true
    64          })
    65          helper.registerAllowedMethod("readJSON", [Map], { m ->
    66              if(m.file == 'testStep_reports.json')
    67                  return [[target: "1234.pdf", mandatory: true]]
    68              if(m.file == 'testStep_links.json')
    69                  return []
    70              if(m.file == 'testStepCategory_errorDetails.json')
    71                  return [message: 'detailed error', category: 'testCategory']
    72              if(m.file == 'testStep_errorDetails.json')
    73                  return [message: 'detailed error']
    74              if(m.text != null)
    75                  return new JsonSlurper().parseText(m.text)
    76          })
    77  
    78          helper.registerAllowedMethod('libraryResource', [String.class], {s ->
    79              if (s == 'metadata/test.yaml') {
    80                  return '''metadata:
    81    name: testStep
    82  '''
    83              } else {
    84                  return '''general:
    85    failOnError: true
    86  '''
    87              }
    88          })
    89  
    90          helper.registerAllowedMethod('file', [Map], { m -> return m })
    91          helper.registerAllowedMethod('string', [Map], { m -> return m })
    92          helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m })
    93          helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
    94              l.each {m ->
    95                  credentials.add(m)
    96                  if (m.credentialsId == 'credFile') {
    97                      binding.setProperty('PIPER_credFile', 'credFileContent')
    98                  } else if (m.credentialsId == 'credToken') {
    99                      binding.setProperty('PIPER_credToken','credTokenContent')
   100                  } else if (m.credentialsId == 'credUsernamePassword') {
   101                      binding.setProperty('PIPER_user', 'userId')
   102                      binding.setProperty('PIPER_password', '********')
   103                  }
   104              }
   105              try {
   106                  c()
   107              } finally {
   108                  binding.setProperty('PIPER_credFile', null)
   109                  binding.setProperty('PIPER_credToken', null)
   110                  binding.setProperty('PIPER_user', null)
   111                  binding.setProperty('PIPER_password', null)
   112              }
   113          })
   114  
   115          helper.registerAllowedMethod('archiveArtifacts', [Map.class], {m ->
   116              artifacts.add(m)
   117              return null
   118          })
   119  
   120          helper.registerAllowedMethod('findFiles', [Map.class], {m -> return null})
   121      }
   122  
   123      @Test
   124      void testPiperExecuteBinDefault() {
   125          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   126          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"fileCredentialsId":"credFile", "tokenCredentialsId":"credToken", "credentialsId":"credUsernamePassword", "dockerImage":"my.Registry/my/image:latest"}')
   127  
   128          List stepCredentials = [
   129              [type: 'file', id: 'fileCredentialsId', env: ['PIPER_credFile']],
   130              [type: 'token', id: 'tokenCredentialsId', env: ['PIPER_credToken']],
   131              [type: 'usernamePassword', id: 'credentialsId', env: ['PIPER_user', 'PIPER_password']],
   132          ]
   133          stepRule.step.piperExecuteBin(
   134              [
   135                  juStabUtils: utils,
   136                  jenkinsUtilsStub: jenkinsUtils,
   137                  testParam: "This is test content",
   138                  script: nullScript
   139              ],
   140              'testStep',
   141              'metadata/test.yaml',
   142              stepCredentials
   143          )
   144          // asserts
   145          assertThat(writeFileRule.files['.pipeline/tmp/metadata/test.yaml'], containsString('name: testStep'))
   146          assertThat(withEnvArgs[0], allOf(startsWith('PIPER_parametersJSON'), containsString('"testParam":"This is test content"')))
   147          assertThat(shellCallRule.shell[2], is('./piper testStep'))
   148          assertThat(credentials.size(), is(3))
   149          assertThat(credentials[0], allOf(hasEntry('credentialsId', 'credFile'), hasEntry('variable', 'PIPER_credFile')))
   150          assertThat(credentials[1], allOf(hasEntry('credentialsId', 'credToken'), hasEntry('variable', 'PIPER_credToken')))
   151          assertThat(credentials[2], allOf(hasEntry('credentialsId', 'credUsernamePassword'), hasEntry('usernameVariable', 'PIPER_user') , hasEntry('passwordVariable', 'PIPER_password')))
   152  
   153          assertThat(dockerExecuteRule.dockerParams.dockerImage, is('my.Registry/my/image:latest'))
   154          assertThat(dockerExecuteRule.dockerParams.stashContent, is([]))
   155  
   156          assertThat(artifacts[0], allOf(hasEntry('artifacts', '1234.pdf'), hasEntry('allowEmptyArchive', false)))
   157      }
   158  
   159      @Test
   160      void testPiperExecuteBinANSCredentialsFromHooksSection() {
   161          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   162          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"fileCredentialsId":"credFile", "tokenCredentialsId":"credToken", "credentialsId":"credUsernamePassword", "dockerImage":"my.Registry/my/image:latest"}')
   163  
   164          def newScript = nullScript
   165          DefaultValueCache.createInstance([hooks: [ans: [serviceKeyCredentialsId: "ansServiceKeyID"]]])
   166  
   167          List stepCredentials = []
   168          stepRule.step.piperExecuteBin(
   169                  [
   170                          juStabUtils: utils,
   171                          jenkinsUtilsStub: jenkinsUtils,
   172                          testParam: "This is test content",
   173                          script: newScript
   174                  ],
   175                  'testStep',
   176                  'metadata/test.yaml',
   177                  stepCredentials
   178          )
   179          // asserts
   180          assertThat(credentials.size(), is(1))
   181          assertThat(credentials[0], allOf(hasEntry('credentialsId', 'ansServiceKeyID'), hasEntry('variable', 'PIPER_ansHookServiceKey')))
   182          DefaultValueCache.reset()
   183      }
   184  
   185      @Test
   186      void testPiperExecuteBinDontResolveCredentialsAndNoCredId() {
   187  
   188          // In case we have a credential entry without Id we drop that silenty.
   189          // Maybe we should revisit that and fail in this case.
   190  
   191          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   192          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"dockerImage":"my.Registry/my/image:latest"}')
   193  
   194          List stepCredentials = [
   195              [type: 'token', env: ['PIPER_credTokenNoResolve'], resolveCredentialsId: false],
   196          ]
   197  
   198          stepRule.step.piperExecuteBin(
   199              [
   200                  juStabUtils: utils,
   201                  jenkinsUtilsStub: jenkinsUtils,
   202                  testParam: "This is test content",
   203                  script: nullScript
   204              ],
   205              'testStep',
   206              'metadata/test.yaml',
   207              stepCredentials
   208          )
   209          assertThat(credentials.size(), is(0))
   210      }
   211  
   212      @Test
   213      void testPiperExecuteBinSomeCredentials() {
   214          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   215          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"fileCredentialsId":"credFile", "tokenCredentialsId":"credToken", "dockerImage":"my.Registry/my/image:latest"}')
   216  
   217          List stepCredentials = [
   218              [type: 'file', id: 'fileCredentialsId', env: ['PIPER_credFile']],
   219              [type: 'token', id: 'tokenCredentialsId', env: ['PIPER_credToken']],
   220              // for the entry below we don't have a config lookup.
   221              [type: 'token', id: 'tokenCredentialsIdNoResolve', env: ['PIPER_credTokenNoResolve'], resolveCredentialsId: false],
   222              [type: 'token', id: 'tokenCredentialsIdNotContainedInConfig', env: ['PIPER_credToken_doesNotMatter']],
   223              [type: 'usernamePassword', id: 'credentialsId', env: ['PIPER_user', 'PIPER_password']],
   224          ]
   225          stepRule.step.piperExecuteBin(
   226              [
   227                  juStabUtils: utils,
   228                  jenkinsUtilsStub: jenkinsUtils,
   229                  testParam: "This is test content",
   230                  script: nullScript
   231              ],
   232              'testStep',
   233              'metadata/test.yaml',
   234              stepCredentials
   235          )
   236          // asserts
   237          assertThat(credentials.size(), is(3))
   238          assertThat(credentials[0], allOf(hasEntry('credentialsId', 'credFile'), hasEntry('variable', 'PIPER_credFile')))
   239          assertThat(credentials[1], allOf(hasEntry('credentialsId', 'credToken'), hasEntry('variable', 'PIPER_credToken')))
   240          assertThat(credentials[2], allOf(hasEntry('credentialsId', 'tokenCredentialsIdNoResolve'), hasEntry('variable', 'PIPER_credTokenNoResolve')))
   241      }
   242  
   243      @Test
   244      void testPiperExecuteBinSSHCredentials() {
   245          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   246          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"sshCredentialsId":"sshKey", "tokenCredentialsId":"credToken"}')
   247  
   248          List sshKey = []
   249          helper.registerAllowedMethod("sshagent", [List, Closure], {s, c ->
   250              sshKey = s
   251              c()
   252          })
   253  
   254          List stepCredentials = [
   255              [type: 'token', id: 'tokenCredentialsId', env: ['PIPER_credToken']],
   256              [type: 'ssh', id: 'sshCredentialsId'],
   257          ]
   258          stepRule.step.piperExecuteBin(
   259              [
   260                  juStabUtils: utils,
   261                  jenkinsUtilsStub: jenkinsUtils,
   262                  testParam: "This is test content",
   263                  script: nullScript
   264              ],
   265              'testStep',
   266              'metadata/test.yaml',
   267              stepCredentials
   268          )
   269          // asserts
   270          assertThat(credentials.size(), is(1))
   271          assertThat(credentials[0], allOf(hasEntry('credentialsId', 'credToken'), hasEntry('variable', 'PIPER_credToken')))
   272          assertThat(sshKey, is(['sshKey']))
   273      }
   274  
   275      @Test
   276      void testPiperExecuteBinNoDockerNoCredentials() {
   277          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   278          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   279  
   280          stepRule.step.piperExecuteBin(
   281              [
   282                  juStabUtils: utils,
   283                  jenkinsUtilsStub: jenkinsUtils,
   284                  testParam: "This is test content",
   285                  script: nullScript
   286              ],
   287              'testStep',
   288              'metadata/test.yaml',
   289              []
   290          )
   291  
   292          assertThat(writeFileRule.files['.pipeline/tmp/metadata/test.yaml'], containsString('name: testStep'))
   293          assertThat(withEnvArgs[0], allOf(startsWith('PIPER_parametersJSON'), containsString('"testParam":"This is test content"')))
   294          assertThat(shellCallRule.shell[2], is('./piper testStep'))
   295          assertThat(credentials.size(), is(0))
   296  
   297          assertThat(dockerExecuteRule.dockerParams.size(), is(0))
   298  
   299          assertThat(artifacts[0], allOf(hasEntry('artifacts', '1234.pdf'), hasEntry('allowEmptyArchive', false)))
   300  
   301      }
   302  
   303      @Test
   304      void testPiperExecuteBinNoReportFound() {
   305          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   306          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   307          helper.registerAllowedMethod('fileExists', [Map], {
   308              return false
   309          })
   310  
   311          exception.expect(AbortException)
   312          exception.expectMessage("Expected to find testStep_reports.json in workspace but it is not there")
   313  
   314          stepRule.step.piperExecuteBin(
   315              [
   316                  juStabUtils: utils,
   317                  jenkinsUtilsStub: jenkinsUtils,
   318                  testParam: "This is test content",
   319                  script: nullScript
   320              ],
   321              'testStep',
   322              'metadata/test.yaml',
   323              [],
   324              true,
   325              false,
   326              false
   327          )
   328      }
   329  
   330      @Test
   331      void testErrorWithCategory() {
   332          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   333          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   334          helper.registerAllowedMethod('sh', [String.class], {s -> throw new AbortException('exit code 1')})
   335  
   336          exception.expect(AbortException)
   337          exception.expectMessage("[testStepCategory] Step execution failed (category: testCategory). Error: detailed error")
   338  
   339          try {
   340              stepRule.step.piperExecuteBin(
   341                  [
   342                      juStabUtils: utils,
   343                      jenkinsUtilsStub: jenkinsUtils,
   344                      testParam: "This is test content",
   345                      script: nullScript
   346                  ],
   347                  'testStepCategory',
   348                  'metadata/test.yaml',
   349                  []
   350              )
   351          } catch (ex) {
   352              assertThat(DebugReport.instance.failedBuild.category, is('testCategory'))
   353              throw ex
   354          }
   355  
   356      }
   357  
   358      @Test
   359      void testErrorWithoutCategory() {
   360          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   361          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   362          helper.registerAllowedMethod('sh', [String.class], {s -> throw new AbortException('exit code 1')})
   363  
   364          exception.expect(AbortException)
   365          exception.expectMessage("[testStep] Step execution failed. Error: detailed error")
   366  
   367          stepRule.step.piperExecuteBin(
   368              [
   369                  juStabUtils: utils,
   370                  jenkinsUtilsStub: jenkinsUtils,
   371                  testParam: "This is test content",
   372                  script: nullScript
   373              ],
   374              'testStep',
   375              'metadata/test.yaml',
   376              []
   377          )
   378      }
   379  
   380      @Test
   381      void testErrorNoDetails() {
   382          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   383          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   384          helper.registerAllowedMethod('sh', [String.class], {s -> throw new AbortException('exit code 1')})
   385  
   386          exception.expect(AbortException)
   387          exception.expectMessage("[noDetailsStep] Step execution failed. Error: hudson.AbortException: exit code 1, please see log file for more details.")
   388  
   389          stepRule.step.piperExecuteBin(
   390              [
   391                  juStabUtils: utils,
   392                  jenkinsUtilsStub: jenkinsUtils,
   393                  testParam: "This is test content",
   394                  script: nullScript
   395              ],
   396              'noDetailsStep',
   397              'metadata/test.yaml',
   398              []
   399          )
   400      }
   401  
   402      @Test
   403      void testRespectPipelineResilienceSetting() {
   404          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   405          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{}')
   406          helper.registerAllowedMethod('sh', [String.class], {s -> throw new AbortException('exit code 1')})
   407  
   408          def unstableCalled
   409          helper.registerAllowedMethod('unstable', [String.class], {s -> unstableCalled = true})
   410  
   411          try {
   412              nullScript.commonPipelineEnvironment.configuration.steps = [handlePipelineStepErrors: [failOnError: false]]
   413  
   414              stepRule.step.piperExecuteBin(
   415                  [
   416                      juStabUtils: utils,
   417                      jenkinsUtilsStub: jenkinsUtils,
   418                      testParam: "This is test content",
   419                      script: nullScript
   420                  ],
   421                  'noDetailsStep',
   422                  'metadata/test.yaml',
   423                  []
   424              )
   425          } finally {
   426              //clean up
   427              nullScript.commonPipelineEnvironment.configuration.steps = [handlePipelineStepErrors: [failOnError: true]]
   428          }
   429          assertThat(unstableCalled, is(true))
   430  
   431      }
   432  
   433      @Test
   434      void testProperStashHandling() {
   435          shellCallRule.setReturnValue('[ -x ./piper ]', 1)
   436          shellCallRule.setReturnValue('./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/test.yaml\'', '{"dockerImage":"test","stashContent":["buildDescriptor"]}')
   437  
   438          stepRule.step.piperExecuteBin(
   439              [
   440                  juStabUtils: utils,
   441                  jenkinsUtilsStub: jenkinsUtils,
   442                  script: nullScript
   443              ],
   444              'testStep',
   445              'metadata/test.yaml',
   446              []
   447          )
   448  
   449          assertThat(dockerExecuteRule.dockerParams.stashContent, is(["buildDescriptor", "pipelineConfigAndTests", "piper-bin", "pipelineStepReports"]))
   450      }
   451  }