Jenkins Job DSL testing with plugins - dynamic DSL with Jenkins Test Harness

I am trying to setup testing for my Job DSL scripts and I’ve managed to come a decent way to get things working and I have hit a snag. This should be a pretty quick and easy question I think.

I want to run a test on setting a hiddenParam on a job, which requires the hidden-parameter plugin. I’m currently getting the following error:

HiddenParametersSpec > Test HiddenParameter FAILED
    groovy.lang.MissingMethodException: No signature of method: javaposse.jobdsl.dsl.helpers.BuildParametersContext.hiddenParam() is applicable for argument types: (String, String, String) values: [test-param, some hidden parameter value, some hidden parameter]
    Possible solutions: fileParam(java.lang.String, java.lang.String), runParam(java.lang.String, java.lang.String, java.lang.String)
        at app//javaposse.jobdsl.dsl.AbstractExtensibleContext.methodMissing(AbstractExtensibleContext.groovy:19)
        at uk.co.dsohub.jenkins.automation.parameter.HiddenParameter.toDsl_closure1(HiddenParameter.groovy:19)
        at uk.co.dsohub.jenkins.automation.parameter.HiddenParameter.toDsl_closure1(HiddenParameter.groovy)
        at app//javaposse.jobdsl.dsl.ContextHelper.executeInContext(ContextHelper.groovy:16)
        at app//javaposse.jobdsl.dsl.Job.parameters(Job.groovy:317)
        at uk.co.dsohub.jenkins.automation.builder.PipelineJobBuilder.build_closure1$_closure3(PipelineJobBuilder.groovy:74)
        at uk.co.dsohub.jenkins.automation.builder.PipelineJobBuilder.build_closure1(PipelineJobBuilder.groovy:73)
        at app//javaposse.jobdsl.dsl.JobParent.processItem(JobParent.groovy:248)
        at app//javaposse.jobdsl.dsl.JobParent.pipelineJob(JobParent.groovy:87)
        at app//uk.co.dsohub.jenkins.automation.builder.PipelineJobBuilder.build(PipelineJobBuilder.groovy:64)
        at uk.co.dsohub.jenkins.automation.parameter.HiddenParametersSpec.Test HiddenParameter(HiddenParameterSpec.groovy:22)

This is where I am using the DSL to apply the hiddenParam:

	@Override
	Closure toDsl() {
		return {
			hiddenParam(
				this.getName(),
				this.getDefaultValue(),
				this.getDescription()
			)
		}
	}

Now, I’ve read this small paragraph on this page:
“The dynamic DSL is only supported when running in Jenkins, e.g. it is not available when running from the command line or in the Playground. Use The Configure Block to generate custom config elements when not running in Jenkins.”

I am using Jenkins Test Harness, so there is an in-memory Jenkins instance being span up, so I’m wondering does this paragraph apply?
“dynamic DSL is only supported when running in Jenkins” - and I have an in-memory instance with Jenkins Test Harness, so does this count as running?

If not, then I guess I am just forced to use a configure block, which is slightly less sexy, but oh well.

I just read some more about Jenkins Job DSL testing and it does seem to suggest that you CAN test Dynamic DSL with Jenkins Test Harness:

“The build script assumes that the Job DSL scripts are located in a sub-directory called jobs . The jobDslVersion and jenkinsVersion settings should match the versions running in the target installation. The dependencies listed as testPlugins are Jenkins plugins that will be installed in the emulated Jenkins instance so that they are available when running the DSL scripts, e.g. for testing extensions or Dynamic DSL.”

Well, I’m still stumped.

I refactored my test class entry point to use DslScriptLoader as shown in the Job DSL wiki and to also get a better like-for-like comparison of applying my Job DSL code in a real Jenkins instance, but I still keep getting No signature of method for a method my plugin should provide.

I read this paragraph:
“The dynamic DSL will not work for all plugins, e.g. if a plugin does not use the @DataBoundConstructor and @DataBoundSetter annotations to declare parameters. In that case The Configure Block can be used to generate the config XML.”
and thought “hmmm maybe the hidden-parameter plugin doesn’t have this?” which wouldn’t make sense as the dynamic DSL works normally when I run my SEED Job.
I search for DataBoundConstructor and found it: hidden-parameter-plugin/src/main/java/com/wangyin/parameter/WHideParameterDefinition.java at deec4ce8b26f286146ca8005d2d39dba3f3d3508 · jenkinsci/hidden-parameter-plugin · GitHub

So that can’t be it.

I double checked that the plugin was being loaded and it definitely is. I ran jenkinsRule.jenkins.pluginManager.plugins.collect { "${it.shortName}:${it.version}" } to check and it’s in the list.

With the help of Claude, I managed to get this sorted.

I needed to update my root test class to use jenkinsRule.jenkins.rootDir as the workspace used for JobManagement instead of File('.'). I think this makes sure that plugins and extensions are loaded into the correct place/context.

My base test class looks like this:

import javaposse.jobdsl.dsl.DslScriptLoader
import javaposse.jobdsl.dsl.GeneratedItems
import javaposse.jobdsl.plugin.JenkinsJobManagement
import jenkins.model.GlobalConfiguration
import org.junit.ClassRule
import org.jvnet.hudson.test.JenkinsRule
import spock.lang.Shared
import spock.lang.Specification


abstract class SpockAbstractBuilderSpec extends Specification {

	@Shared
	@ClassRule
	JenkinsRule jenkinsRule = new JenkinsRule()

	GeneratedItems runScript(String script) {
		def workspace = jenkinsRule.jenkins.rootDir
		def jobManagement = new JenkinsJobManagement(System.out, [:], workspace)
		new DslScriptLoader(jobManagement).runScript(script)
	}


	GeneratedItems runScriptFile(String filePath) {
		runScript(this.getClass().getResource(filePath).text)
	}
}