currently i try to create a project to centralize the generation of job on my jenkins : i use jenkins job dsl 1.77 and try to follow this explanation : https://github.com/jenkinsci/job-dsl-plugin/wiki/Testing-DSL-Scripts
my env is : gradle 8 and jdk 11 on unix env (ubuntu)
here i follow the code :
// build.gradle
plugins {
id 'groovy'
}
sourceSets {
jobs {
groovy {
srcDirs 'src/jobs'
compileClasspath += main.compileClasspath
}
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
src {
groovy {
srcDir 'src/main/groovy'
}
}
test {
groovy {
srcDir 'src/test/groovy'
}
}
}
repositories {
mavenCentral()
maven { url 'https://repo.jenkins-ci.org/releases/' }
jcenter{url "https://jcenter.bintray.com/"}
}
configurations {
testPlugins {}
// see JENKINS-45512
testCompile {
exclude group: 'xalan'
exclude group: 'xerces'
}
}
configurations.all*.exclude group: 'xalan'
dependencies {
implementation 'org.codehaus.groovy:groovy:2.5.14'
implementation ("org.jenkins-ci.plugins:job-dsl-core:${jobDslVersion}") {
exclude module: 'xstream'
}
testCompile 'org.spockframework:spock-core:1.3-groovy-2.5'
testImplementation 'org.spockframework:spock-core:2.0-M5-groovy-3.0'
testImplementation 'cglib:cglib-nodep:2.2.2' // used by Spock
// Jenkins test harness dependencies
testImplementation('org.jenkins-ci.main:jenkins-test-harness:2146.v6b_f8b_1cb_d12d') { //2.34 2146.v6b_f8b_1cb_d12d
exclude group: 'org.netbeans.modules', module: 'org-netbeans-insane'
}
testImplementation("org.jenkins-ci.main:jenkins-war:${jenkinsVersion}") {
exclude group: 'org.jenkins-ci.ui', module: 'bootstrap'
}
testCompile("org.jenkins-ci.main:jenkins-war:${jenkinsVersion}") {
exclude group: 'org.jenkins-ci.ui', module: 'bootstrap'
}
// Job DSL plugin including plugin dependencies
testImplementation "org.jenkins-ci.plugins:job-dsl:${jobDslVersion}"
testImplementation "org.jenkins-ci.plugins:job-dsl:${jobDslVersion}@jar"
testImplementation 'org.jenkins-ci.plugins:structs:1.20@jar'
testImplementation 'org.jenkins-ci.plugins:script-security:1.54@jar'
testImplementation "org.jenkins-ci.main:jenkins-core:${jenkinsVersion}"
testCompile "org.jenkins-ci.plugins:job-dsl:${jobDslVersion}"
testCompile "org.jenkins-ci.plugins:job-dsl:${jobDslVersion}@jar"
testCompile 'org.jenkins-ci.plugins:structs:1.20@jar'
testCompile 'org.jenkins-ci.plugins:script-security:1.54@jar'
// Plugins to install in test instance
testPlugins 'org.jenkins-ci.plugins:cloudbees-folder:5.14'
testPlugins 'org.jenkins-ci.plugins:credentials:2.1.10'
testPlugins 'org.jenkins-ci.plugins:cvs:2.13'
testPlugins 'org.jenkins-ci.plugins:ghprb:1.40.0'
testPlugins 'org.jenkins-ci.plugins:token-macro:2.5'
testPlugins 'org.jenkins-ci.plugins.workflow:workflow-cps-global-lib:2.7'
}
task resolveTestPlugins(type: Copy) {
from configurations.testPlugins
into new File(sourceSets.test.output.resourcesDir, 'test-dependencies')
include '*.hpi'
include '*.jpi'
def mapping = [:]
doFirst {
configurations.testPlugins.resolvedConfiguration.resolvedArtifacts.each {
mapping[it.file.name] = "${it.name}.${it.extension}"
}
}
rename { mapping[it] }
doLast {
List<String> baseNames = source*.name.collect { mapping[it] }.collect { it[0..it.lastIndexOf('.') - 1] }
new File(destinationDir, 'index').setText(baseNames.join('n'), 'UTF-8')
}
}
test {
dependsOn tasks.resolveTestPlugins
inputs.files sourceSets.jobs.groovy.srcDirs
useJUnitPlatform()
}
```
```
# gradle.properties
jobDslVersion=1.77
jenkinsVersion= 2.445
// JobRulesSpec.groovy
package com.example
import groovy.util.FileNameFinder
import javaposse.jobdsl.dsl.DslScriptLoader
import javaposse.jobdsl.plugin.JenkinsJobManagement
import org.junit.ClassRule
import org.jvnet.hudson.test.JenkinsRule
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
class JobRulesSpec extends Specification {
@Shared
@ClassRule
private JenkinsRule jenkinsRule = new JenkinsRule()
@Unroll
def 'test script #file.name'() { //File file
given:
println "==============> ${jenkinsRule.instance}"
def jobManagement = new JenkinsJobManagement(System.out, [:], new File('.'))
when:
new DslScriptLoader(jobManagement).runScript(file.text)
then:
noExceptionThrown()
where:
file << new FileNameFinder().getFileNames('src/jobs', '**/*.groovy').collect { new File(it) }
}
}
result
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="net.regnology.JobRulesSpec" tests="1" skipped="0" failures="1" errors="0" timestamp="2024-02-19T16:49:41" hostname="INV-PC-432" time="0.683">
<properties/>
<testcase name="test script job.groovy" classname="net.regnology.JobRulesSpec" time="0.683">
<failure message="Expected no exception to be thrown, but got 'java.lang.IllegalStateException'" type="org.spockframework.runtime.UnallowedExceptionThrownError">Expected no exception to be thrown, but got 'java.lang.IllegalStateException'
at app//spock.lang.Specification.noExceptionThrown(Specification.java:118)
at net.regnology.JobRulesSpec.test script #file.name(jobsRulesSpec.groovy:27)
Caused by: java.lang.IllegalStateException: Jenkins.instance is missing. Read the documentation of Jenkins.getInstanceOrNull to see what you are doing wrong.
at jenkins.model.Jenkins.get(Jenkins.java:819)
at javaposse.jobdsl.plugin.LookupStrategy.lambda$static$0(LookupStrategy.java:19)
at javaposse.jobdsl.plugin.LookupStrategy.getContext(LookupStrategy.java:57)
at javaposse.jobdsl.plugin.LookupStrategy.getItem(LookupStrategy.java:42)
at javaposse.jobdsl.plugin.JenkinsJobManagement.createOrUpdateConfig(JenkinsJobManagement.java:136)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedJobs_closure4(AbstractDslScriptLoader.groovy:204)
at groovy.lang.Closure.call(Closure.java:412)
at groovy.lang.Closure.call(Closure.java:428)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedJobs(AbstractDslScriptLoader.groovy:197)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedItems(AbstractDslScriptLoader.groovy:184)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts_closure1(AbstractDslScriptLoader.groovy:63)
at groovy.lang.Closure.call(Closure.java:412)
at groovy.lang.Closure.call(Closure.java:428)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScript(AbstractDslScriptLoader.groovy:87)
at net.regnology.JobRulesSpec.test script #file.name(jobsRulesSpec.groovy:24)
</failure>
</testcase>
<system-out><![CDATA[==============> null
Processing provided DSL script
]]></system-out>
<system-err><![CDATA[Feb 19, 2024 5:49:41 PM javaposse.jobdsl.plugin.JenkinsJobManagement createOrUpdateConfig
INFO: createOrUpdateConfig for test
]]></system-err>
</testsuite>
i take same question on jenkins test harness repository but from authors of jenkins test harness seems not possible : https://github.com/jenkinsci/jenkins-test-harness/issues/732
if you have any idea that’s great thx
regards
i try to implement unit test on job definitions into gradle project
2
Answers
i decide to use junit instead of spock works better now
First you should make sure not to add spock-core in 1.x and 2.x version on your classpath.
E.g. that one should do it:
You do miss the needed dependency to let Spock recognize the ClassRule of your test.
The dependency
is needed in your build.gradle and Jenkins should start as expected.
See https://spockframework.org/spock/docs/2.3/extensions.html#_classrule which does mention this:
Because you failed to add that dependency it failed to honor that Rule and failed your test.