jenkinsjenkins-pipeline-unit

How to mock `pwsh` with libraryResource in Jenkins PipelineUnit


I am trying to write unit tests for the custom steps in my Jenkins Shared Library. I've landed on using Gradle and JenkinsPipelineUnit (via the articles linked at the end of this post), and I am getting stuck on mocking the pwsh step that runs a PowerShell script. My custom step is in vars/getRepo.groovy:

def call() {
  def repo = pwsh returnStdout: true, label: 'get repo', script: "${libraryResource 'Get-Repo.ps1'}"

  return repo.trim()
}

The test is:

import org.junit.*
import com.lesfurets.jenkins.unit.*
import static groovy.test.GroovyAssert.*

class GetRepoTest extends BasePipelineTest {
  def getRepo

  @Before
  void setUp() {
    super.setUp()
    // set up mocks
    def reponame = 'myRepoName'
    helper.registerAllowedMethod("pwsh", [Boolean, String, String], { p -> return reponame })

    // load getRepo
    getRepo = loadScript("vars/getRepo.groovy")
  }

  @Test
  void testCall() {
    // call getRepo and check result
    def result = getRepo()
    assert 'myRepoName'.equals(result)
  }
}

The test fails; to me it seems like I'm either not mocking the pwsh step correctly, or the inclusion of the libraryResource function is throwing something off.

groovy.lang.GroovyRuntimeException: Library Resource not found with path Get-Repo.ps1

There's definitely native support for mocking libraryResource in the JenkinsPipelineUnit package, but I can't figure out how to use it. From the JPU repo:

/**
* Method interceptor for 'libraryResource' in Shared libraries
* The resource from shared library should have been added to the url classloader in advance
*/
def libraryResourceInterceptor = { m ->
  def stream = gse.groovyClassLoader.getResourceAsStream(m as String)
  if (stream) {
    def string = IOUtils.toString(stream, Charset.forName("UTF-8"))
            IOUtils.closeQuietly(stream)
            return string
        } else {
            throw new GroovyRuntimeException("Library Resource not found with path $m")
        }
    }

There's the error it's throwing, so it's somehow using this native mock. What is the 'url classloader' mentioned in the comment? I did try putting the ps1 file in the resources/ dir in this project, with no change in behavior.

Many thanks to these two tutorials on getting me this far:

I am also doing my best to document my journey to getting these tests working in my own repo., feel free to check it out.


Solution

  • I'm not sure exactly how I landed on it, but I believe I saw the function signature in either one of my own failed tests or someone else's.

    The signature to mock pwsh (and presumably, powershell) in Jenkins Unit tests turns out to be [HashMap], so therefore the whole mock is:

    helper.registerAllowedMethod('pwsh', [HashMap], { <whatever you want to return> })