diff --git a/pom.xml b/pom.xml index 543449b5..1974026b 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ jenkinsci/${project.artifactId}-plugin true ivy + false diff --git a/src/test/java/org/jenkinsci/plugins/workflow/cps/global/CompilationErrorsExceptionTest.java b/src/test/java/org/jenkinsci/plugins/workflow/cps/global/CompilationErrorsExceptionTest.java index 2f705d00..0f321a27 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/cps/global/CompilationErrorsExceptionTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/cps/global/CompilationErrorsExceptionTest.java @@ -5,6 +5,7 @@ import java.util.Collections; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.codehaus.groovy.control.MultipleCompilationErrorsException; import org.jenkinsci.plugins.workflow.cps.CpsCompilationErrorsException; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; @@ -13,20 +14,33 @@ import org.jenkinsci.plugins.workflow.libs.GlobalLibraries; import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration; import org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +@WithGitSampleRepo +class CompilationErrorsExceptionTest { + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; -public class CompilationErrorsExceptionTest { - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + } @Issue("JENKINS-40109") - @Test public void errorInSrcStaticLibrary() throws Exception { + @Test + void errorInSrcStaticLibrary() throws Exception { sampleRepo.init(); sampleRepo.write("src/foo/Test.groovy", "package foo; public class Test { bad syntax } "); sampleRepo.git("add", "src"); @@ -43,7 +57,8 @@ public class CompilationErrorsExceptionTest { } @Issue("JENKINS-40109") - @Test public void errorInSrcDynamicLibrary() throws Exception { + @Test + void errorInSrcDynamicLibrary() throws Exception { sampleRepo.init(); sampleRepo.write("src/foo/Test.groovy", "package foo; public class Test { bad syntax } "); sampleRepo.git("add", "src"); @@ -66,7 +81,8 @@ public class CompilationErrorsExceptionTest { } @Issue("JENKINS-40109") - @Test public void errorInVars() throws Exception { + @Test + void errorInVars() throws Exception { sampleRepo.init(); sampleRepo.write("vars/mymagic.groovy", "def call() { bad, syntax }"); sampleRepo.git("add", "vars"); @@ -88,5 +104,4 @@ public class CompilationErrorsExceptionTest { r.assertLogContains(CpsCompilationErrorsException.class.getName(), b); r.assertLogContains("unexpected token: bad", b); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/cps/global/GrapeTest.java b/src/test/java/org/jenkinsci/plugins/workflow/cps/global/GrapeTest.java index 9f3eefd9..efaa40b3 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/cps/global/GrapeTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/cps/global/GrapeTest.java @@ -29,7 +29,9 @@ import hudson.model.Run; import hudson.model.TaskListener; import java.io.File; -import java.util.Arrays; +import java.nio.charset.StandardCharsets; +import java.util.List; + import jenkins.model.Jenkins; import org.apache.commons.io.FileUtils; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; @@ -40,30 +42,35 @@ import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration; import org.jenkinsci.plugins.workflow.libs.LibraryRetriever; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; -import org.junit.Test; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsSessionRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension; @Issue("JENKINS-26192") -public class GrapeTest { +class GrapeTest { - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsSessionRule story = new JenkinsSessionRule(); + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + @RegisterExtension + private final JenkinsSessionExtension story = new JenkinsSessionExtension(); - @Test public void useBinary() throws Throwable { + @Test + void useBinary() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "src/pkg/Lists.groovy"), - "package pkg\n" + - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import org.apache.commons.collections.primitives.ArrayIntList\n" + - "static def arrayInt(script) {\n" + - " script.semaphore 'wait'\n" + - " new ArrayIntList()\n" + - "}"); + """ + package pkg + @Grab('commons-primitives:commons-primitives:1.0') + import org.apache.commons.collections.primitives.ArrayIntList + static def arrayInt(script) { + script.semaphore 'wait' + new ArrayIntList() + }""", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("echo(/got ${pkg.Lists.arrayInt(this)}/)", true)); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); @@ -78,16 +85,18 @@ public class GrapeTest { }); } - @Test public void var() throws Throwable { + @Test + void var() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "vars/one.groovy"), - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import org.apache.commons.collections.primitives.ArrayIntList\n" + - "def call() {\n" + - " def list = new ArrayIntList()\n" + - " list.incrModCount()\n" + - " list.modCount\n" + - "}"); + """ + @Grab('commons-primitives:commons-primitives:1.0') + import org.apache.commons.collections.primitives.ArrayIntList + def call() { + def list = new ArrayIntList() + list.incrModCount() + list.modCount + }""", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("echo(/${one()} + ${one()} = ${one() + one()}/)", true)); j.assertLogContains("1 + 1 = 2", j.buildAndAssertSuccess(p)); @@ -96,25 +105,29 @@ public class GrapeTest { // TODO test transitive dependencies; need to find something in Central which has a dependency not in this plugin’s test classpath and which could be used easily from a script - @Test public void nonexistentLibrary() throws Throwable { + @Test + void nonexistentLibrary() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "src/pkg/X.groovy"), - "package pkg\n" + - "@Grab('net.nowhere:nonexistent:99.9')\n" + - "static def run() {}"); + """ + package pkg + @Grab('net.nowhere:nonexistent:99.9') + static def run() {}""", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("pkg.X.run()", true)); j.assertLogContains("net.nowhere", j.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); }); } - @Test public void nonexistentImport() throws Throwable { + @Test + void nonexistentImport() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "src/pkg/X.groovy"), - "package pkg\n" + - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import net.nowhere.Nonexistent\n" + - "static def run() {new Nonexistent()}"); + """ + package pkg + @Grab('commons-primitives:commons-primitives:1.0') + import net.nowhere.Nonexistent + static def run() {new Nonexistent()}""", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("pkg.X.run()", true)); j.assertLogContains("net.nowhere.Nonexistent", j.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); @@ -123,8 +136,9 @@ public class GrapeTest { // TODO test alternate Maven repositories - @Ignore("TODO MissingMethodException: No signature of method: static com.google.common.base.CharMatcher.whitespace() is applicable for argument types: () values: []") - @Test public void overrideCoreLibraries() throws Throwable { + @Disabled("TODO MissingMethodException: No signature of method: static com.google.common.base.CharMatcher.whitespace() is applicable for argument types: () values: []") + @Test + void overrideCoreLibraries() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "src/pkg/Strings.groovy"), "package pkg\n" + @@ -132,23 +146,25 @@ public class GrapeTest { "import com.google.common.base.CharMatcher\n" + "static def hasWhitespace(text) {\n" + " CharMatcher.whitespace().matchesAnyOf(text)\n" + - "}"); + "}", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("echo(/checking ${pkg.Strings.hasWhitespace('hello world')}/)", true)); j.assertLogContains("checking true", j.buildAndAssertSuccess(p)); }); } - @Ignore("TODO fails on CI and inside a Docker container, though for different reasons: `download failed` vs. `/var/maven/.groovy/grapes/resolved-caller-all-caller-working61.xml (No such file or directory)`; and a test-scoped dep on docker-workflow:1.7 does not help") - @Test public void useSource() throws Throwable { + @Disabled("TODO fails on CI and inside a Docker container, though for different reasons: `download failed` vs. `/var/maven/.groovy/grapes/resolved-caller-all-caller-working61.xml (No such file or directory)`; and a test-scoped dep on docker-workflow:1.7 does not help") + @Test + void useSource() throws Throwable { story.then(j -> { FileUtils.write(new File(libroot(), "src/pkg/Dokker.groovy"), - "package pkg\n" + - "@Grapes([@Grab('org.jenkins-ci.plugins:docker-workflow:1.7'), @Grab('org.jenkins-ci.plugins:docker-commons:1.3.1')])\n" + - "import org.jenkinsci.plugins.docker.workflow.Docker\n" + - "static def stuff(script, body) {\n" + - " new Docker(script).node {body()}\n" + - "}"); + """ + package pkg + @Grapes([@Grab('org.jenkins-ci.plugins:docker-workflow:1.7'), @Grab('org.jenkins-ci.plugins:docker-commons:1.3.1')]) + import org.jenkinsci.plugins.docker.workflow.Docker + static def stuff(script, body) { + new Docker(script).node {body()} + }""", StandardCharsets.UTF_8); WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("pkg.Dokker.stuff(this) {semaphore 'wait'; writeFile file: 'x', text: 'CPS-transformed'; echo(/ran ${readFile 'x'}/)}", true)); WorkflowRun b = p.scheduleBuild2(0).waitForStart(); @@ -163,50 +179,58 @@ public class GrapeTest { }); } - private File libroot() throws Exception { + private File libroot() { File lib = new File(Jenkins.get().getRootDir(), "somelib"); LibraryConfiguration cfg = new LibraryConfiguration("somelib", new LocalRetriever(lib)); cfg.setImplicit(true); cfg.setDefaultVersion("fixed"); - GlobalLibraries.get().setLibraries(Arrays.asList(cfg)); + GlobalLibraries.get().setLibraries(List.of(cfg)); return lib; } private static final class LocalRetriever extends LibraryRetriever { private final File lib; + LocalRetriever(File lib) { this.lib = lib; } - @Override public void retrieve(String name, String version, boolean changelog, FilePath target, Run run, TaskListener listener) throws Exception { + + @Override + public void retrieve(String name, String version, boolean changelog, FilePath target, Run run, TaskListener listener) throws Exception { new FilePath(lib).copyRecursiveTo(target); } - @Override public void retrieve(String name, String version, FilePath target, Run run, TaskListener listener) throws Exception { + + @Override + public void retrieve(String name, String version, FilePath target, Run run, TaskListener listener) throws Exception { retrieve(name, version, false, target, run, listener); } } - @Test public void outsideLibrary() throws Throwable { + @Test + void outsideLibrary() throws Throwable { story.then(j -> { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import org.apache.commons.collections.primitives.ArrayIntList\n" + - "echo(/got ${new ArrayIntList()}/)", false)); + """ + @Grab('commons-primitives:commons-primitives:1.0') + import org.apache.commons.collections.primitives.ArrayIntList + echo(/got ${new ArrayIntList()}/)""", false)); j.assertLogContains("got []", j.buildAndAssertSuccess(p)); }); } - @Test public void outsideLibrarySandbox() throws Throwable { + @Test + void outsideLibrarySandbox() throws Throwable { story.then(j -> { WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import org.apache.commons.collections.primitives.ArrayIntList\n" + - "new ArrayIntList()", true)); + """ + @Grab('commons-primitives:commons-primitives:1.0') + import org.apache.commons.collections.primitives.ArrayIntList + new ArrayIntList()""", true)); // Even assuming signature approvals, we do not want to allow Grape to be used from sandboxed scripts. ScriptApproval.get().approveSignature("new org.apache.commons.collections.primitives.ArrayIntList"); j.assertLogContains("Annotation Grab cannot be used in the sandbox", j.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); }); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSource.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSource.java index 683431ff..437d73f0 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSource.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSource.java @@ -1,6 +1,5 @@ package org.jenkinsci.plugins.workflow.libs; -import edu.umd.cs.findbugs.annotations.NonNull; import hudson.AbortException; import hudson.FilePath; import hudson.Launcher; diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSourceDuringFetch.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSourceDuringFetch.java index bc839f68..ba333134 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSourceDuringFetch.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/FailingSCMSourceDuringFetch.java @@ -1,20 +1,11 @@ package org.jenkinsci.plugins.workflow.libs; -import edu.umd.cs.findbugs.annotations.NonNull; import hudson.AbortException; -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.Run; import hudson.model.TaskListener; -import hudson.scm.ChangeLogParser; -import hudson.scm.SCM; -import hudson.scm.SCMRevisionState; import jenkins.scm.api.*; -import jenkins.scm.impl.mock.MockSCMRevision; -import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.File; + import java.io.IOException; public class FailingSCMSourceDuringFetch extends FailingSCMSource { diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/FolderLibrariesTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/FolderLibrariesTest.java index 79cf1239..d7d62874 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/FolderLibrariesTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/FolderLibrariesTest.java @@ -48,28 +48,50 @@ import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.cps.GlobalVariable; import org.jenkinsci.plugins.workflow.cps.Snippetizer; -import org.jenkinsci.plugins.workflow.cps.global.GrapeTest; import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import org.junit.Test; -import static org.junit.Assert.*; -import static org.junit.Assume.assumeFalse; -import org.junit.ClassRule; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockAuthorizationStrategy; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +class FolderLibrariesTest { -public class FolderLibrariesTest { + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private final GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule(); + private final GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule(); - @Rule public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule) throws Throwable { + r = rule; + sampleRepo1.before(); + sampleRepo2.before(); + } + + @AfterEach + void afterEach() { + sampleRepo1.after(); + sampleRepo2.after(); + } - @Test public void configRoundtrip() throws Exception { + @Test + void configRoundtrip() throws Exception { Folder d = r.jenkins.createProject(Folder.class, "d"); r.configRoundtrip(d); assertNull(d.getProperties().get(FolderLibraries.class)); @@ -77,15 +99,16 @@ public class FolderLibrariesTest { bar.setDefaultVersion("master"); bar.setImplicit(true); bar.setAllowVersionOverride(false); - d.getProperties().add(new FolderLibraries(Arrays.asList(bar))); + d.getProperties().add(new FolderLibraries(List.of(bar))); r.configRoundtrip(d); FolderLibraries prop = d.getProperties().get(FolderLibraries.class); assertNotNull(prop); List libs = prop.getLibraries(); - r.assertEqualDataBoundBeans(Arrays.asList(bar), libs); + r.assertEqualDataBoundBeans(List.of(bar), libs); } - @Test public void registration() throws Exception { + @Test + void registration() throws Exception { sampleRepo1.init(); sampleRepo1.write("src/generic/Lib.groovy", "package generic; class Lib {static String CONST = 'generic'}"); sampleRepo1.git("add", "src"); @@ -108,7 +131,8 @@ public class FolderLibrariesTest { } @Issue("JENKINS-32400") // one approach - @Test public void loadVarForFolder() throws Exception { + @Test + void loadVarForFolder() throws Exception { sampleRepo1.init(); sampleRepo1.write("src/stuff/Lib.groovy", "package stuff; class Lib {static String CONST = 'stuff'}"); sampleRepo1.write("vars/p.groovy", "def call() {echo(/found some ${stuff.Lib.CONST}/)}"); @@ -130,7 +154,8 @@ public class FolderLibrariesTest { assertThat(html, not(containsString("Handling of <p>."))); } - @Test public void replay() throws Exception { + @Test + void replay() throws Exception { sampleRepo1.init(); String somethingCode = "package pkg; class Something {@NonCPS String toString() {'the first version'}}"; sampleRepo1.write("src/pkg/Something.groovy", somethingCode); @@ -168,8 +193,8 @@ public class FolderLibrariesTest { r.assertLogContains("subsequently running the second version", r.assertBuildStatusSuccess(b3)); } - /** @see GrapeTest#outsideLibrarySandbox */ - @Test public void noGrape() throws Exception { + @Test + void noGrape() throws Exception { Folder d = r.jenkins.createProject(Folder.class, "d"); d.getProperties().add(new FolderLibraries(List.of(LibraryTestUtils.defineLibraryUsingGrab("grape", sampleRepo1)))); WorkflowJob p = d.createProject(WorkflowJob.class, "p"); @@ -178,8 +203,9 @@ public class FolderLibrariesTest { } @Issue("JENKINS-43019") - @Test public void classCastException() throws Exception { - assumeFalse("Too slow, prone to timing out before getting to build #51", Functions.isWindows()); + @Test + void classCastException() throws Exception { + assumeFalse(Functions.isWindows(), "Too slow, prone to timing out before getting to build #51"); sampleRepo1.init(); sampleRepo1.write("src/pkg/Obj.groovy", "package pkg; public class Obj implements Serializable {public Obj() {}}"); sampleRepo1.write("vars/objs.groovy", "@groovy.transform.Field final pkg.Obj OBJ = new pkg.Obj()"); @@ -192,10 +218,11 @@ public class FolderLibrariesTest { ScriptApproval.get().approveSignature("method java.security.ProtectionDomain getCodeSource"); ScriptApproval.get().approveSignature("method java.security.CodeSource getLocation"); String script = - "def descr(c) {/${c.classLoader} < ${c.classLoader.parent} @ ${c.protectionDomain.codeSource?.location}/}\n" + - "echo(/this: ${descr(this.getClass())} Obj: ${descr(pkg.Obj)} objs: ${descr(objs.getClass())} objs.OBJ: ${descr(objs.OBJ.getClass())}/)\n" + - "pkg.Obj obj = objs.OBJ\n" + - "echo(/loaded $obj/)"; + """ + def descr(c) {/${c.classLoader} < ${c.classLoader.parent} @ ${c.protectionDomain.codeSource?.location}/} + echo(/this: ${descr(this.getClass())} Obj: ${descr(pkg.Obj)} objs: ${descr(objs.getClass())} objs.OBJ: ${descr(objs.OBJ.getClass())}/) + pkg.Obj obj = objs.OBJ + echo(/loaded $obj/)"""; { // Trusted lib (control): GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("global-objs", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.createProject(WorkflowJob.class, "p"); @@ -214,7 +241,8 @@ public class FolderLibrariesTest { } @Issue("SECURITY-1422") - @Test public void checkDefaultVersionRestricted() throws Exception { + @Test + void checkDefaultVersionRestricted() throws Exception { sampleRepo1.init(); sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo1.git("add", "vars"); @@ -227,7 +255,7 @@ public class FolderLibrariesTest { r.jenkins.setAuthorizationStrategy(s); LibraryConfiguration foo = new LibraryConfiguration("foo", new SCMSourceRetriever(new GitSCMSource(sampleRepo1.toString()))); Folder f = r.jenkins.createProject(Folder.class, "f"); - f.getProperties().add(new FolderLibraries(Arrays.asList(foo))); + f.getProperties().add(new FolderLibraries(List.of(foo))); JenkinsRule.WebClient wc = r.createWebClient(); wc.setThrowExceptionOnFailingStatusCode(false); WebRequest req = new WebRequest(new URL(wc.getContextPath() + f.getUrl() + "/descriptorByName/" + diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalLibrariesTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalLibrariesTest.java index b32b7341..7a4cd1e3 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalLibrariesTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalLibrariesTest.java @@ -26,8 +26,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import hudson.security.Permission; import java.net.URL; @@ -37,37 +37,53 @@ import jenkins.model.Jenkins; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.htmlunit.HttpMethod; import org.htmlunit.WebRequest; import org.htmlunit.html.HtmlPage; import org.htmlunit.util.NameValuePair; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockAuthorizationStrategy; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +@WithGitSampleRepo +class GlobalLibrariesTest { -public class GlobalLibrariesTest { + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + } - @Test public void configRoundtrip() throws Exception { + @Test + void configRoundtrip() throws Exception { r.configRoundtrip(); configRoundtrip(r, GlobalLibraries.get(), Jenkins.ADMINISTER); } @Issue("SECURITY-1422") - @Test public void checkDefaultVersionRestricted() throws Exception { + @Test + void checkDefaultVersionRestricted() throws Exception { checkDefaultVersionRestricted(r, sampleRepo, GlobalLibraries.get()); } - @Test public void allowedGrape() throws Exception { + @Test + void allowedGrape() throws Exception { GlobalLibraries.get().setLibraries(List.of(LibraryTestUtils.defineLibraryUsingGrab("grape", sampleRepo))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('grape@master') import pkg.Wrapper; echo(/should be able to run ${pkg.Wrapper.list()}/)", true)); @@ -85,7 +101,7 @@ static void checkDefaultVersionRestricted(JenkinsRule r, GitSampleRepoRule sampl .grant(Jenkins.ADMINISTER).everywhere().to("admin"); r.jenkins.setAuthorizationStrategy(s); LibraryConfiguration foo = new LibraryConfiguration("foo", new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString()))); - gl.setLibraries(Arrays.asList(foo)); + gl.setLibraries(List.of(foo)); JenkinsRule.WebClient wc = r.createWebClient(); wc.setThrowExceptionOnFailingStatusCode(false); WebRequest req = new WebRequest(new URL(wc.getContextPath() + "/descriptorByName/" + @@ -113,7 +129,7 @@ static void configRoundtrip(JenkinsRule r, AbstractGlobalLibraries gl, Permissio bar.setDefaultVersion("master"); bar.setImplicit(true); bar.setAllowVersionOverride(false); - gl.setLibraries(Arrays.asList(bar)); + gl.setLibraries(List.of(bar)); r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy(). grant(alicePrivileges).everywhere().to("alice") @@ -122,9 +138,9 @@ static void configRoundtrip(JenkinsRule r, AbstractGlobalLibraries gl, Permissio assertThat(configurePage.getWebResponse().getContentAsString(), containsString("https://phony.jenkins.io/bar.git")); r.submit(configurePage.getFormByName("config")); // JenkinsRule.configRoundtrip expanded to include login List libs = gl.getLibraries(); - r.assertEqualDataBoundBeans(Arrays.asList(bar), libs); + r.assertEqualDataBoundBeans(List.of(bar), libs); libs = gl.getLibraries(); - r.assertEqualDataBoundBeans(Arrays.asList(bar), libs); + r.assertEqualDataBoundBeans(List.of(bar), libs); boolean noBar = true; for (LibraryConfiguration lib : libs) { if ("bar".equals(lib.getName())) { @@ -132,6 +148,6 @@ static void configRoundtrip(JenkinsRule r, AbstractGlobalLibraries gl, Permissio r.assertEqualDataBoundBeans(lib.getCachingConfiguration(), cachingConfiguration); } } - assertFalse("Missing a library called bar (should not happen)", noBar); + assertFalse(noBar, "Missing a library called bar (should not happen)"); } } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalUntrustedLibrariesTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalUntrustedLibrariesTest.java index 5ea5c832..708e0fce 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalUntrustedLibrariesTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/GlobalUntrustedLibrariesTest.java @@ -28,36 +28,51 @@ import java.util.List; import jenkins.model.Jenkins; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +@WithGitSampleRepo +class GlobalUntrustedLibrariesTest { -public class GlobalUntrustedLibrariesTest { + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + } - @Test public void configRoundtrip() throws Exception { + @Test + void configRoundtrip() throws Exception { r.configRoundtrip(); GlobalLibrariesTest.configRoundtrip(r, GlobalUntrustedLibraries.get(), Jenkins.READ, Jenkins.MANAGE); } @Issue("SECURITY-1422") - @Test public void checkDefaultVersionRestricted() throws Exception { + @Test + void checkDefaultVersionRestricted() throws Exception { GlobalLibrariesTest.checkDefaultVersionRestricted(r, sampleRepo, GlobalUntrustedLibraries.get()); } - @Test public void noGrape() throws Exception { + @Test + void noGrape() throws Exception { GlobalUntrustedLibraries.get().setLibraries(List.of(LibraryTestUtils.defineLibraryUsingGrab("grape", sampleRepo))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('grape@master') import pkg.Wrapper; echo(/should not have been able to run ${pkg.Wrapper.list()}/)", true)); r.assertLogContains("Annotation Grab cannot be used in the sandbox", r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryAdderTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryAdderTest.java index 062c1774..aff377b9 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryAdderTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryAdderTest.java @@ -49,62 +49,82 @@ import static org.hamcrest.Matchers.nullValue; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.cps.GlobalVariable; -import org.jenkinsci.plugins.workflow.cps.global.GrapeTest; import org.jenkinsci.plugins.workflow.cps.global.UserDefinedGlobalVariable; import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import org.jenkinsci.plugins.workflow.libs.ClasspathAdder.Addition; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.WithoutJenkins; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.recipes.LocalData; -public class LibraryAdderTest { +@WithJenkins +class LibraryAdderTest { + + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private final GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule(); + private final GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @Rule public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule) throws Throwable { + r = rule; + sampleRepo1.before(); + sampleRepo2.before(); + } + + @AfterEach + void afterEach() { + sampleRepo1.after(); + sampleRepo2.after(); + } - @Test public void smokes() throws Exception { - sampleRepo.init(); + @Test + void smokes() throws Exception { + sampleRepo1.init(); String lib = "package pkg; class Lib {static String CONST = 'constant'}"; - sampleRepo.write("src/pkg/Lib.groovy", lib); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + sampleRepo1.write("src/pkg/Lib.groovy", lib); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); String script = "@Library('stuff@master') import static pkg.Lib.*; echo(/using ${CONST}/)"; p.setDefinition(new CpsFlowDefinition(script, true)); r.assertLogContains("using constant", r.buildAndAssertSuccess(p)); - sampleRepo.git("tag", "1.0"); - sampleRepo.write("src/pkg/Lib.groovy", lib.replace("constant", "modified")); - sampleRepo.git("commit", "--all", "--message=modified"); + sampleRepo1.git("tag", "1.0"); + sampleRepo1.write("src/pkg/Lib.groovy", lib.replace("constant", "modified")); + sampleRepo1.git("commit", "--all", "--message=modified"); r.assertLogContains("using modified", r.buildAndAssertSuccess(p)); p.setDefinition(new CpsFlowDefinition(script.replace("master", "1.0"), true)); r.assertLogContains("using constant", r.buildAndAssertSuccess(p)); } - @Test public void usingInterpolation() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'initial'}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - sampleRepo.git("tag", "initial"); - sampleRepo.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'modified'}"); - sampleRepo.git("commit", "--all", "--message=modified"); + @Test + void usingInterpolation() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'initial'}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + sampleRepo1.git("tag", "initial"); + sampleRepo1.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'modified'}"); + sampleRepo1.git("commit", "--all", "--message=modified"); LibraryConfiguration stuff = new LibraryConfiguration("stuff", new SCMRetriever( - new GitSCM(Collections.singletonList(new UserRemoteConfig(sampleRepo.fileUrl(), null, null, null)), + new GitSCM(Collections.singletonList(new UserRemoteConfig(sampleRepo1.fileUrl(), null, null, null)), Collections.singletonList(new BranchSpec("${library.stuff.version}")), null, null, Collections.emptyList()))); stuff.setDefaultVersion("master"); @@ -122,12 +142,13 @@ public class LibraryAdderTest { } @Issue("JENKINS-41497") - @Test public void dontIncludeChangesetsOverriden() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration lc = new LibraryConfiguration("dont_include_changes", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + @Test + void dontIncludeChangesetsOverridden() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something special'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration lc = new LibraryConfiguration("dont_include_changes", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); lc.setIncludeInChangesets(false); GlobalLibraries.get().setLibraries(Collections.singletonList(lc)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -137,9 +158,9 @@ public class LibraryAdderTest { WorkflowRun a = r.buildAndAssertSuccess(p); r.assertLogContains("something special", a); } - sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something even more special'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=library_commit"); + sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something even more special'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=library_commit"); try (WorkspaceList.Lease lease = r.jenkins.toComputer().getWorkspaceList().acquire(base)) { WorkflowRun b = r.buildAndAssertSuccess(p); List> changeSets = b.getChangeSets(); @@ -155,12 +176,13 @@ public class LibraryAdderTest { } @Issue("JENKINS-41497") - @Test public void includeChangesetsOverridden() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration lc = new LibraryConfiguration("include_changes", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + @Test + void includeChangesetsOverridden() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something special'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration lc = new LibraryConfiguration("include_changes", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); lc.setIncludeInChangesets(true); GlobalLibraries.get().setLibraries(Collections.singletonList(lc)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -169,9 +191,9 @@ public class LibraryAdderTest { try (WorkspaceList.Lease lease = r.jenkins.toComputer().getWorkspaceList().acquire(base)) { WorkflowRun a = r.buildAndAssertSuccess(p); } - sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something even more special'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=library_commit"); + sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something even more special'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=library_commit"); try (WorkspaceList.Lease lease = r.jenkins.toComputer().getWorkspaceList().acquire(base)) { WorkflowRun b = r.buildAndAssertSuccess(p); List> changeSets = b.getChangeSets(); @@ -179,15 +201,16 @@ public class LibraryAdderTest { } } - @Test public void globalVariable() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); - sampleRepo.write("vars/myecho.txt", "Says something very special!"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void globalVariable() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/myecho.groovy", "def call() {echo 'something special'}"); + sampleRepo1.write("vars/myecho.txt", "Says something very special!"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("echo-utils", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('echo-utils@master') import myecho; myecho()", true)); WorkflowRun b = r.buildAndAssertSuccess(p); @@ -197,22 +220,30 @@ public class LibraryAdderTest { assertEquals("Says something very special!", ((UserDefinedGlobalVariable) var).getHelpHtml()); } - @Test public void dynamicLibraries() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'constant'}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void dynamicLibraries() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Lib.groovy", "package pkg; class Lib {static String CONST = 'constant'}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - DynamicResolver.remote = sampleRepo.toString(); + DynamicResolver.remote = sampleRepo1.toString(); p.setDefinition(new CpsFlowDefinition("@Library('dynamic') import pkg.Lib; echo(/using ${Lib.CONST}/)", true)); r.assertLogContains("using constant", r.buildAndAssertSuccess(p)); } - @TestExtension("dynamicLibraries") public static class DynamicResolver extends LibraryResolver { - @Override public boolean isTrusted() { + + @TestExtension("dynamicLibraries") + public static class DynamicResolver extends LibraryResolver { + + static String remote; + + @Override + public boolean isTrusted() { return false; } - static String remote; - @Override public Collection forJob(Job job, Map libraryVersions) { + + @Override + public Collection forJob(Job job, Map libraryVersions) { if (libraryVersions.containsKey("dynamic")) { LibraryConfiguration cfg = new LibraryConfiguration("dynamic", new SCMSourceRetriever(new GitSCMSource(null, remote, "", "*", "", true))); cfg.setDefaultVersion("master"); @@ -223,16 +254,17 @@ public class LibraryAdderTest { } } - @Test public void undefinedLibraries() throws Exception { + @Test + void undefinedLibraries() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('nonexistent') _", true)); r.assertLogContains(Messages.LibraryDecorator_could_not_find_any_definition_of_librari(Collections.singletonList("nonexistent")), r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); } - /** @see GrapeTest */ - @Test public void grape() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/semver/Version.groovy", + @Test + void grape() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/semver/Version.groovy", "package semver\n" + "@Grab('com.vdurmont:semver4j:2.0.1') import com.vdurmont.semver4j.Semver\n" + // https://github.com/vdurmont/semver4j#using-gradle "public class Version implements Serializable {\n" + @@ -243,27 +275,29 @@ public class LibraryAdderTest { " new Semver(v).isGreaterThan(version)\n" + " }\n" + "}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("semver", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("semver", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "@Library('semver@master') import semver.Version\n" + - "echo(/1.2.0 > 1.0.0? ${new Version('1.2.0').isGreaterThan('1.0.0')}/)\n" + - "echo(/1.0.0 > 1.2.0? ${new Version('1.0.0').isGreaterThan('1.2.0')}/)", true)); + """ + @Library('semver@master') import semver.Version + echo(/1.2.0 > 1.0.0? ${new Version('1.2.0').isGreaterThan('1.0.0')}/) + echo(/1.0.0 > 1.2.0? ${new Version('1.0.0').isGreaterThan('1.2.0')}/)""", true)); WorkflowRun b = r.buildAndAssertSuccess(p); r.assertLogContains("1.2.0 > 1.0.0? true", b); r.assertLogContains("1.0.0 > 1.2.0? false", b); } - @Test public void noReplayTrustedLibraries() throws Exception { - sampleRepo.init(); + @Test + void noReplayTrustedLibraries() throws Exception { + sampleRepo1.init(); String originalMessage = "must not be edited"; String originalScript = "def call() {echo '" + originalMessage + "'}"; - sampleRepo.write("vars/trusted.groovy", originalScript); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("trusted", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + sampleRepo1.write("vars/trusted.groovy", originalScript); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("trusted", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('trusted@master') import trusted; trusted()", true)); WorkflowRun b1 = r.buildAndAssertSuccess(p); @@ -276,14 +310,15 @@ public class LibraryAdderTest { } @Issue({"JENKINS-38021", "JENKINS-31484"}) - @Test public void gettersAndSetters() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/config.groovy", "class config implements Serializable {private String foo; public String getFoo() {return(/loaded ${this.foo}/)}; public void setFoo(String value) {this.foo = value.toUpperCase()}}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void gettersAndSetters() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/config.groovy", "class config implements Serializable {private String foo; public String getFoo() {return(/loaded ${this.foo}/)}; public void setFoo(String value) {this.foo = value.toUpperCase()}}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("config", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('config@master') _; timeout(1) {config.foo = 'bar'; echo(/set to $config.foo/)}", false)); r.assertLogContains("set to loaded BAR", r.buildAndAssertSuccess(p)); @@ -294,32 +329,36 @@ public class LibraryAdderTest { } @Issue("JENKINS-56682") - @Test public void scriptFieldsWhereInitializerUsesLibrary() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Foo.groovy", "package pkg; class Foo { }"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void scriptFieldsWhereInitializerUsesLibrary() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Foo.groovy", "package pkg; class Foo { }"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("lib", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "@Library('lib@master') import pkg.Foo\n" + - "import groovy.transform.Field\n" + - "@Field f = new Foo()\n" + - "@Field static g = new Foo()\n", true)); + """ + @Library('lib@master') import pkg.Foo + import groovy.transform.Field + @Field f = new Foo() + @Field static g = new Foo() + """, true)); r.buildAndAssertSuccess(p); } - @Test public void srcTestNotOnClassPath() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/test/Foo.groovy", "package test; class Foo { }"); - sampleRepo.write("src/test/foo/Bar.groovy", "package test.foo; class Bar { }"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void srcTestNotOnClassPath() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/test/Foo.groovy", "package test; class Foo { }"); + sampleRepo1.write("src/test/foo/Bar.groovy", "package test.foo; class Bar { }"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("lib", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('lib@master') import test.Foo", true)); WorkflowRun b = r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)); @@ -328,14 +367,15 @@ public class LibraryAdderTest { } @Issue("SECURITY-2422") - @Test public void libraryNamesAreNotUsedAsBuildDirectoryPaths() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/globalLibVar.groovy", "def call() { echo('global library') }"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void libraryNamesAreNotUsedAsBuildDirectoryPaths() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/globalLibVar.groovy", "def call() { echo('global library') }"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); sampleRepo2.init(); LibraryConfiguration globalLib = new LibraryConfiguration("global", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); globalLib.setDefaultVersion("master"); globalLib.setImplicit(true); GlobalLibraries.get().setLibraries(Collections.singletonList(globalLib)); @@ -359,14 +399,15 @@ public class LibraryAdderTest { } @Issue("SECURITY-2586") - @Test public void libraryNamesAreNotUsedAsCacheDirectories() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/globalLibVar.groovy", "def call() { echo('global library') }"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void libraryNamesAreNotUsedAsCacheDirectories() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/globalLibVar.groovy", "def call() { echo('global library') }"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); sampleRepo2.init(); LibraryConfiguration globalLib = new LibraryConfiguration("library", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); globalLib.setDefaultVersion("master"); globalLib.setImplicit(true); globalLib.setCachingConfiguration(new LibraryCachingConfiguration(60, "")); @@ -399,16 +440,16 @@ public class LibraryAdderTest { @LocalData @Test - public void correctLibraryDirectoryUsedWhenResumingOldBuild() throws Exception { + void correctLibraryDirectoryUsedWhenResumingOldBuild() throws Exception { // LocalData was captured after saving the build in the following snippet: /* - sampleRepo.init(); - sampleRepo.write("vars/foo.groovy", "def call() { echo('called Foo') }"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + sampleRepo1.init(); + sampleRepo1.write("vars/foo.groovy", "def call() { echo('called Foo') }"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("lib", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( "@Library('lib@master') _\n" + @@ -426,20 +467,20 @@ public void correctLibraryDirectoryUsedWhenResumingOldBuild() throws Exception { @Issue("JENKINS-66898") @Test - public void parallelBuildsDontInterfereWithExpiredCache() throws Throwable { + void parallelBuildsDontInterfereWithExpiredCache() throws Throwable { // Add a few files to the library so the deletion is not too fast // Before fixing JENKINS-66898 this test was failing almost always // with a build failure - sampleRepo.init(); - sampleRepo.write("vars/foo.groovy", "def call() { echo 'foo' }"); - sampleRepo.write("vars/bar.groovy", "def call() { echo 'bar' }"); - sampleRepo.write("vars/foo2.groovy", "def call() { echo 'foo2' }"); - sampleRepo.write("vars/foo3.groovy", "def call() { echo 'foo3' }"); - sampleRepo.write("vars/foo4.groovy", "def call() { echo 'foo4' }"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + sampleRepo1.init(); + sampleRepo1.write("vars/foo.groovy", "def call() { echo 'foo' }"); + sampleRepo1.write("vars/bar.groovy", "def call() { echo 'bar' }"); + sampleRepo1.write("vars/foo2.groovy", "def call() { echo 'foo2' }"); + sampleRepo1.write("vars/foo3.groovy", "def call() { echo 'foo3' }"); + sampleRepo1.write("vars/foo4.groovy", "def call() { echo 'foo4' }"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); LibraryConfiguration config = new LibraryConfiguration("library", - new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); config.setDefaultVersion("master"); config.setImplicit(true); config.setCachingConfiguration(new LibraryCachingConfiguration(30, null)); @@ -467,24 +508,26 @@ public void parallelBuildsDontInterfereWithExpiredCache() throws Throwable { @Issue("JENKINS-68544") @WithoutJenkins - @Test public void className() { + @Test + void className() { assertThat(LibraryAdder.LoadedLibraries.className("/path/to/lib/src/some/pkg/Type.groovy", "/path/to/lib/src"), is("some.pkg.Type")); assertThat(LibraryAdder.LoadedLibraries.className("C:\\path\\to\\lib\\src\\some\\pkg\\Type.groovy", "C:\\path\\to\\lib\\src"), is("some.pkg.Type")); assertThat(LibraryAdder.LoadedLibraries.className("C:\\path\\to\\Extra\\lib\\src\\some\\pkg\\Type.groovy", "C:\\path\\to\\Extra\\lib\\src"), is("some.pkg.Type")); } @Issue("JENKINS-73769") - @Test public void libraryPathsAreUsedInBuildDirectoryPathGeneration() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/globalLibVar.groovy", "def call() { echo('global library root') }"); - sampleRepo.write("libs/lib1/vars/globalLibVar.groovy", "def call() { echo('global library 1') }"); - sampleRepo.write("libs/lib2/vars/globalLibVar.groovy", "def call() { echo('global library 2') }"); - sampleRepo.write("libs/lib3/vars/.gitignore", "# empty library"); - sampleRepo.git("add", "libs"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void libraryPathsAreUsedInBuildDirectoryPathGeneration() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/globalLibVar.groovy", "def call() { echo('global library root') }"); + sampleRepo1.write("libs/lib1/vars/globalLibVar.groovy", "def call() { echo('global library 1') }"); + sampleRepo1.write("libs/lib2/vars/globalLibVar.groovy", "def call() { echo('global library 2') }"); + sampleRepo1.write("libs/lib3/vars/.gitignore", "# empty library"); + sampleRepo1.git("add", "libs"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); sampleRepo2.init(); - SCMBasedRetriever retriever = new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)); + SCMBasedRetriever retriever = new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true)); LibraryConfiguration globalLib = new LibraryConfiguration("global", retriever); globalLib.setDefaultVersion("master"); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingCleanupTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingCleanupTest.java index ff30c86e..14b92d50 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingCleanupTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingCleanupTest.java @@ -30,27 +30,36 @@ import java.time.ZonedDateTime; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.not; import static org.hamcrest.io.FileMatchers.anExistingDirectory; import static org.hamcrest.io.FileMatchers.anExistingFile; -public class LibraryCachingCleanupTest { +@WithJenkins +@WithGitSampleRepo +class LibraryCachingCleanupTest { + + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; - @Rule - public JenkinsRule r = new JenkinsRule(); - @Rule - public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + } @Test - public void smokes() throws Throwable { + void smokes() throws Throwable { sampleRepo.init(); sampleRepo.write("vars/foo.groovy", "def call() { echo 'foo' }"); sampleRepo.git("add", "vars"); @@ -82,7 +91,7 @@ public void smokes() throws Throwable { } @Test - public void preSecurity2586() throws Throwable { + void preSecurity2586() throws Throwable { FilePath cache = LibraryCachingConfiguration.getGlobalLibrariesCacheDir().child("name").child("version"); cache.mkdirs(); cache.child(LibraryCachingConfiguration.LAST_READ_FILE).touch(System.currentTimeMillis()); @@ -90,5 +99,4 @@ public void preSecurity2586() throws Throwable { assertThat(new File(cache.getRemote()), not(anExistingDirectory())); assertThat(new File(cache.getParent().getRemote()), not(anExistingDirectory())); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingConfigurationTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingConfigurationTest.java index a3689e27..6b83430d 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingConfigurationTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryCachingConfigurationTest.java @@ -29,85 +29,90 @@ import java.io.File; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.WithoutJenkins; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; import static org.hamcrest.io.FileMatchers.anExistingDirectory; import static org.hamcrest.io.FileMatchers.anExistingFile; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@WithJenkins +@WithGitSampleRepo +class LibraryCachingConfigurationTest { -public class LibraryCachingConfigurationTest { - @Rule - public JenkinsRule r = new JenkinsRule(); - @Rule - public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; private LibraryCachingConfiguration nullVersionConfig; private LibraryCachingConfiguration oneVersionConfig; private LibraryCachingConfiguration multiVersionConfig; private LibraryCachingConfiguration substringVersionConfig; - private static int REFRESH_TIME_MINUTES = 23; - private static int NO_REFRESH_TIME_MINUTES = 0; + private static final int REFRESH_TIME_MINUTES = 23; + private static final int NO_REFRESH_TIME_MINUTES = 0; - private static String NULL_EXCLUDED_VERSION = null; - private static String NULL_INCLUDED_VERSION = null; + private static final String NULL_EXCLUDED_VERSION = null; + private static final String NULL_INCLUDED_VERSION = null; - private static String ONE_EXCLUDED_VERSION = "branch-1"; + private static final String ONE_EXCLUDED_VERSION = "branch-1"; - private static String ONE_INCLUDED_VERSION = "branch-1i"; + private static final String ONE_INCLUDED_VERSION = "branch-1i"; - private static String MULTIPLE_EXCLUDED_VERSIONS_1 = "main"; + private static final String MULTIPLE_EXCLUDED_VERSIONS_1 = "main"; - private static String MULTIPLE_INCLUDED_VERSIONS_1 = "master"; + private static final String MULTIPLE_INCLUDED_VERSIONS_1 = "master"; - private static String MULTIPLE_EXCLUDED_VERSIONS_2 = "branch-2"; + private static final String MULTIPLE_EXCLUDED_VERSIONS_2 = "branch-2"; - private static String MULTIPLE_INCLUDED_VERSIONS_2 = "branch-2i"; + private static final String MULTIPLE_INCLUDED_VERSIONS_2 = "branch-2i"; - private static String MULTIPLE_EXCLUDED_VERSIONS_3 = "branch-3"; - private static String MULTIPLE_INCLUDED_VERSIONS_3 = "branch-3i"; + private static final String MULTIPLE_EXCLUDED_VERSIONS_3 = "branch-3"; + private static final String MULTIPLE_INCLUDED_VERSIONS_3 = "branch-3i"; - private static String SUBSTRING_EXCLUDED_VERSIONS_1 = "feature/test-substring-exclude"; + private static final String SUBSTRING_EXCLUDED_VERSIONS_1 = "feature/test-substring-exclude"; - private static String SUBSTRING_INCLUDED_VERSIONS_1 = "feature_include/test-substring"; + private static final String SUBSTRING_INCLUDED_VERSIONS_1 = "feature_include/test-substring"; - private static String SUBSTRING_EXCLUDED_VERSIONS_2 = "test-other-substring-exclude"; - private static String SUBSTRING_INCLUDED_VERSIONS_2 = "test-other-substring-include"; + private static final String SUBSTRING_EXCLUDED_VERSIONS_2 = "test-other-substring-exclude"; + private static final String SUBSTRING_INCLUDED_VERSIONS_2 = "test-other-substring-include"; - private static String MULTIPLE_EXCLUDED_VERSIONS = + private static final String MULTIPLE_EXCLUDED_VERSIONS = MULTIPLE_EXCLUDED_VERSIONS_1 + " " + MULTIPLE_EXCLUDED_VERSIONS_2 + " " + MULTIPLE_EXCLUDED_VERSIONS_3; - private static String MULTIPLE_INCLUDED_VERSIONS = + private static final String MULTIPLE_INCLUDED_VERSIONS = MULTIPLE_INCLUDED_VERSIONS_1 + " " + MULTIPLE_INCLUDED_VERSIONS_2 + " " + MULTIPLE_INCLUDED_VERSIONS_3; - private static String SUBSTRING_EXCLUDED_VERSIONS = + private static final String SUBSTRING_EXCLUDED_VERSIONS = "feature/ other-substring"; - private static String SUBSTRING_INCLUDED_VERSIONS = + private static final String SUBSTRING_INCLUDED_VERSIONS = "feature_include/ other-substring"; - private static String NEVER_EXCLUDED_VERSION = "never-excluded-version"; + private static final String NEVER_EXCLUDED_VERSION = "never-excluded-version"; - @Before - public void createCachingConfiguration() { + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; nullVersionConfig = new LibraryCachingConfiguration(REFRESH_TIME_MINUTES, NULL_EXCLUDED_VERSION, NULL_INCLUDED_VERSION); oneVersionConfig = new LibraryCachingConfiguration(NO_REFRESH_TIME_MINUTES, ONE_EXCLUDED_VERSION, ONE_INCLUDED_VERSION); multiVersionConfig = new LibraryCachingConfiguration(REFRESH_TIME_MINUTES, MULTIPLE_EXCLUDED_VERSIONS, MULTIPLE_INCLUDED_VERSIONS); @@ -117,34 +122,34 @@ public void createCachingConfiguration() { @Issue("JENKINS-66045") // NPE getting excluded versions @Test @WithoutJenkins - public void npeGetExcludedVersions() { + void npeGetExcludedVersions() { assertFalse(nullVersionConfig.isExcluded(NEVER_EXCLUDED_VERSION)); } @Test @WithoutJenkins - public void getRefreshTimeMinutes() { + void getRefreshTimeMinutes() { assertThat(nullVersionConfig.getRefreshTimeMinutes(), is(REFRESH_TIME_MINUTES)); assertThat(oneVersionConfig.getRefreshTimeMinutes(), is(NO_REFRESH_TIME_MINUTES)); } @Test @WithoutJenkins - public void getRefreshTimeMilliseconds() { + void getRefreshTimeMilliseconds() { assertThat(nullVersionConfig.getRefreshTimeMilliseconds(), is(60 * 1000L * REFRESH_TIME_MINUTES)); assertThat(oneVersionConfig.getRefreshTimeMilliseconds(), is(60 * 1000L * NO_REFRESH_TIME_MINUTES)); } @Test @WithoutJenkins - public void isRefreshEnabled() { + void isRefreshEnabled() { assertTrue(nullVersionConfig.isRefreshEnabled()); assertFalse(oneVersionConfig.isRefreshEnabled()); } @Test @WithoutJenkins - public void getExcludedVersionsStr() { + void getExcludedVersionsStr() { assertThat(nullVersionConfig.getExcludedVersionsStr(), is(NULL_EXCLUDED_VERSION)); assertThat(oneVersionConfig.getExcludedVersionsStr(), is(ONE_EXCLUDED_VERSION)); assertThat(multiVersionConfig.getExcludedVersionsStr(), is(MULTIPLE_EXCLUDED_VERSIONS)); @@ -153,7 +158,7 @@ public void getExcludedVersionsStr() { @Test @WithoutJenkins - public void getIncludedVersionsStr() { + void getIncludedVersionsStr() { assertThat(nullVersionConfig.getIncludedVersionsStr(), is(NULL_INCLUDED_VERSION)); assertThat(oneVersionConfig.getIncludedVersionsStr(), is(ONE_INCLUDED_VERSION)); assertThat(multiVersionConfig.getIncludedVersionsStr(), is(MULTIPLE_INCLUDED_VERSIONS)); @@ -162,7 +167,7 @@ public void getIncludedVersionsStr() { @Test @WithoutJenkins - public void isExcluded() { + void isExcluded() { assertFalse(nullVersionConfig.isExcluded(NULL_EXCLUDED_VERSION)); assertFalse(nullVersionConfig.isExcluded("")); @@ -193,7 +198,7 @@ public void isExcluded() { @Issue("JENKINS-69135") //"Versions to include" feature for caching @Test @WithoutJenkins - public void isIncluded() { + void isIncluded() { assertFalse(nullVersionConfig.isIncluded(NULL_INCLUDED_VERSION)); assertFalse(nullVersionConfig.isIncluded("")); @@ -209,7 +214,7 @@ public void isIncluded() { } @Test - public void clearCache() throws Exception { + void clearCache() throws Exception { sampleRepo.init(); sampleRepo.write("vars/foo.groovy", "def call() { echo 'foo' }"); sampleRepo.git("add", "vars"); @@ -239,7 +244,7 @@ public void clearCache() throws Exception { //Exclusion takes precedence @Issue("JENKINS-69135") //"Versions to include" feature for caching @Test - public void clearCacheConflict() throws Exception { + void clearCacheConflict() throws Exception { sampleRepo.init(); sampleRepo.write("vars/foo.groovy", "def call() { echo 'foo' }"); sampleRepo.git("add", "vars"); @@ -266,7 +271,7 @@ public void clearCacheConflict() throws Exception { @Issue("JENKINS-69135") //"Versions to include" feature for caching @Test - public void clearCacheIncludedVersion() throws Exception { + void clearCacheIncludedVersion() throws Exception { sampleRepo.init(); sampleRepo.write("vars/foo.groovy", "def call() { echo 'foo' }"); sampleRepo.git("add", "vars"); @@ -302,5 +307,4 @@ public void clearCacheIncludedVersion() throws Exception { assertThat(new File(cache2.getRemote()), not(anExistingDirectory())); assertThat(new File(cache2.withSuffix("-name.txt").getRemote()), not(anExistingFile())); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryConfigurationTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryConfigurationTest.java index c91a4627..0d6b674a 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryConfigurationTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryConfigurationTest.java @@ -24,28 +24,40 @@ package org.jenkinsci.plugins.workflow.libs; -import java.util.Collections; - import hudson.plugins.git.GitSCM; import org.hamcrest.Matchers; -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.Rule; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; -public class LibraryConfigurationTest { +@WithJenkins +class LibraryConfigurationTest { - @Rule public JenkinsRule r = new JenkinsRule(); + private JenkinsRule r; + + @BeforeEach + void beforeEach(JenkinsRule rule) { + r = rule; + } @Issue("JENKINS-38550") - @Test public void visibleRetrievers() throws Exception { + @Test + void visibleRetrievers() { assertThat(r.jenkins.getDescriptorByType(LibraryConfiguration.DescriptorImpl.class).getRetrieverDescriptors(), - Matchers.containsInAnyOrder(r.jenkins.getDescriptorByType(SCMSourceRetriever.DescriptorImpl.class), r.jenkins.getDescriptorByType(SCMRetriever.DescriptorImpl.class))); + Matchers.containsInAnyOrder(r.jenkins.getDescriptorByType(SCMSourceRetriever.DescriptorImpl.class), r.jenkins.getDescriptorByType(SCMRetriever.DescriptorImpl.class))); } @Issue("JENKINS-59527") - @Test public void validDefaultVersionAndName() { + @Test + void validDefaultVersionAndName() { String libraryName = "valid-name"; String defaultVersion = "master"; @@ -57,7 +69,8 @@ public class LibraryConfigurationTest { } @Issue("JENKINS-59527") - @Test public void spacesDefaultVersionAndName() { + @Test + void spacesDefaultVersionAndName() { String libraryName = " valid-name "; String defaultVersion = " master "; @@ -69,7 +82,8 @@ public class LibraryConfigurationTest { } @Issue("JENKINS-59527") - @Test public void emptyStringDefaultVersionAndName() { + @Test + void emptyStringDefaultVersionAndName() { String libraryName = ""; String defaultVersion = ""; @@ -81,7 +95,8 @@ public class LibraryConfigurationTest { } @Issue("JENKINS-59527") - @Test public void nullDefaultVersionAndName() { + @Test + void nullDefaultVersionAndName() { String libraryName = null; String defaultVersion = null; @@ -91,7 +106,4 @@ public class LibraryConfigurationTest { assertNull(cfg.getName()); assertNull(cfg.getDefaultVersion()); } - - - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryDecoratorTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryDecoratorTest.java index 1df4ccea..42cb44ed 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryDecoratorTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryDecoratorTest.java @@ -27,9 +27,11 @@ import hudson.AbortException; import hudson.model.Result; import java.io.File; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.HashMap; + import org.apache.commons.io.FileUtils; import org.jenkinsci.plugins.workflow.actions.ErrorAction; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; @@ -37,38 +39,55 @@ import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.support.storage.SimpleXStreamFlowNodeStorage; -import static org.junit.Assert.*; -import org.junit.Test; -import org.junit.ClassRule; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; -public class LibraryDecoratorTest { +@WithJenkins +class LibraryDecoratorTest { - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + + @BeforeEach + void beforeEach(JenkinsRule rule) { + r = rule; + } - @Test public void singleLibrary() throws Exception { + @Test + void singleLibrary() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - FileUtils.write(new File(p.getRootDir(), "libs/foo/pkg/Lib.groovy"), "package pkg; class Lib {static String CONST = 'constant'}"); + FileUtils.write(new File(p.getRootDir(), "libs/foo/pkg/Lib.groovy"), "package pkg; class Lib {static String CONST = 'constant'}", StandardCharsets.UTF_8); p.setDefinition(new CpsFlowDefinition("@Library('foo') import pkg.Lib; echo(/using ${Lib.CONST}/)", true)); r.assertLogContains("using constant", r.buildAndAssertSuccess(p)); } - @Test public void severalLibraries() throws Exception { + @Test + void severalLibraries() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); // stub syntax; @TestExtension GlobalVariable would allow s/new one()()/one()/ p.setDefinition(new CpsFlowDefinition("@Library(['x', 'y']) import one; import two; echo(/loaded ${new one()()} and ${new two()()}/)", true)); - FileUtils.write(new File(p.getRootDir(), "libs/x/one.groovy"), "def call() {1}"); - FileUtils.write(new File(p.getRootDir(), "libs/y/two.groovy"), "def call() {2}"); + FileUtils.write(new File(p.getRootDir(), "libs/x/one.groovy"), "def call() {1}", StandardCharsets.UTF_8); + FileUtils.write(new File(p.getRootDir(), "libs/y/two.groovy"), "def call() {2}", StandardCharsets.UTF_8); r.assertLogContains("loaded 1 and 2", r.buildAndAssertSuccess(p)); } - @TestExtension public static class TestAdder extends ClasspathAdder { - @Override public List add(CpsFlowExecution execution, List libraries, HashMap changelogs) throws Exception { + @TestExtension + public static class TestAdder extends ClasspathAdder { + + @Override + public List add(CpsFlowExecution execution, List libraries, HashMap changelogs) throws Exception { List additions = new ArrayList<>(); for (String library : libraries) { additions.add(new Addition(new File(((WorkflowRun) execution.getOwner().getExecutable()).getParent().getRootDir(), "libs/" + library).toURI().toURL(), false)); @@ -79,7 +98,8 @@ public class LibraryDecoratorTest { } @Issue("JENKINS-39450") - @Test public void malformedAnnotation() throws Exception { + @Test + void malformedAnnotation() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library(\"stuff@$BRANCH_NAME\") _", true)); r.assertLogContains("‘stuff@$BRANCH_NAME’", r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); @@ -95,21 +115,27 @@ public class LibraryDecoratorTest { r.buildAndAssertSuccess(p); // legal, if pointless } - @Test public void adderError() throws Exception { + @Test + void adderError() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('stuff') import /* irrelevant */ java.lang.Void", true)); r.assertLogContains("failed to load [stuff]", r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); } - @TestExtension("adderError") public static class ErroneousAdder extends ClasspathAdder { - @Override public List add(CpsFlowExecution execution, List libraries, HashMap changelogs) throws Exception { + + @TestExtension("adderError") + public static class ErroneousAdder extends ClasspathAdder { + + @Override + public List add(CpsFlowExecution execution, List libraries, HashMap changelogs) throws Exception { throw new AbortException("failed to load " + libraries); } } @Issue("JENKINS-57085") - @Test public void stackTraceFilenames() throws Exception { + @Test + void stackTraceFilenames() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - FileUtils.write(new File(p.getRootDir(), "libs/foo/pkg/Lib.groovy"), "package pkg; class Lib {static def fail() {throw new Exception('oops')}}"); + FileUtils.write(new File(p.getRootDir(), "libs/foo/pkg/Lib.groovy"), "package pkg; class Lib {static def fail() {throw new Exception('oops')}}", StandardCharsets.UTF_8); p.setDefinition(new CpsFlowDefinition("@Library('foo') import pkg.Lib; Lib.fail()", true)); WorkflowRun b = r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)); r.assertLogContains("java.lang.Exception: oops", b); @@ -123,5 +149,4 @@ public class LibraryDecoratorTest { // Comparing the actual StackTraceElement arrays is hopeless: https://github.com/x-stream/xstream/pull/145#discussion_r278613917 assertEquals(xml, xml2); } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryMemoryTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryMemoryTest.java index 49a9282d..2dbae171 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryMemoryTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryMemoryTest.java @@ -36,30 +36,46 @@ import java.util.logging.Level; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.codehaus.groovy.reflection.ClassInfo; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.cps.CpsFlowExecution; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.support.storage.BulkFlowNodeStorage; -import org.junit.Before; -import static org.junit.Assert.assertFalse; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.LoggerRule; +import org.jvnet.hudson.test.LogRecorder; import org.jvnet.hudson.test.MemoryAssert; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; -public class LibraryMemoryTest { +import static org.junit.jupiter.api.Assertions.assertFalse; - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @Rule public LoggerRule logging = new LoggerRule().record(CpsFlowExecution.class, Level.FINER); +@WithJenkins +@WithGitSampleRepo +class LibraryMemoryTest { + + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; + @SuppressWarnings("unused") + private final LogRecorder logging = new LogRecorder().record(CpsFlowExecution.class, Level.FINER); private static final List> LOADERS = new ArrayList<>(); + + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + LOADERS.clear(); + } + + @SuppressWarnings("unused") public static void register(Object o) { System.err.println("registering " + o); for (ClassLoader loader = o.getClass().getClassLoader(); !(loader instanceof PluginManager.UberClassLoader); loader = loader.getParent()) { @@ -68,13 +84,9 @@ public static void register(Object o) { } } - @Before - public void cleanUp() { - LOADERS.clear(); - } - @Issue("JENKINS-50223") - @Test public void loaderReleased() throws Exception { + @Test + void loaderReleased() throws Exception { sampleRepo.init(); sampleRepo.write("src/p/C.groovy", "package p; class C {}"); sampleRepo.write("vars/leak.groovy", "def call() {def c = node {new p.C()}; [this, c].each {" + LibraryMemoryTest.class.getName() + ".register(it)}}"); @@ -96,7 +108,8 @@ public void cleanUp() { } } - @Test public void loaderReleasedWithGrab() throws Exception { + @Test + void loaderReleasedWithGrab() throws Exception { { // http-builder loads xerces stuff that XStream has special handling for, and if BulkFlowNodeStorage // is first initialized by a Pipeline that uses @Grab, the grabbed classes will be available when @@ -132,5 +145,4 @@ public void cleanUp() { MemoryAssert.assertGC(loaderRef, false); } } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryStepTest.java index fd5df157..8124aba3 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryStepTest.java @@ -30,9 +30,8 @@ import hudson.model.Result; import hudson.plugins.git.BranchSpec; import hudson.plugins.git.GitSCM; -import hudson.plugins.git.SubmoduleConfig; import hudson.plugins.git.UserRemoteConfig; -import hudson.plugins.git.extensions.GitSCMExtension; + import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -40,7 +39,6 @@ import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; import jenkins.plugins.git.traits.BranchDiscoveryTrait; -import jenkins.scm.api.trait.SCMSourceTrait; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.cps.Snippetizer; import org.jenkinsci.plugins.workflow.cps.SnippetizerTester; @@ -48,24 +46,46 @@ import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.steps.StepConfigTester; -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; @Issue("JENKINS-39450") -public class LibraryStepTest { +@WithJenkins +class LibraryStepTest { + + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private final GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule(); + private final GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @Rule public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule) throws Throwable { + r = rule; + sampleRepo1.before(); + sampleRepo2.before(); + } + + @AfterEach + void afterEach() { + sampleRepo1.after(); + sampleRepo2.after(); + } - @Test public void configRoundtrip() throws Exception { + @Test + void configRoundtrip() throws Exception { StepConfigTester stepTester = new StepConfigTester(r); SnippetizerTester snippetizerTester = new SnippetizerTester(r); LibraryStep s = new LibraryStep("foo"); @@ -73,7 +93,7 @@ public class LibraryStepTest { snippetizerTester.assertRoundTrip(s, "library 'foo'"); s = new LibraryStep("foo@master"); GitSCMSource scmSource = new GitSCMSource("https://nowhere.net/"); - scmSource.setTraits(Collections.singletonList(new BranchDiscoveryTrait())); + scmSource.setTraits(Collections.singletonList(new BranchDiscoveryTrait())); scmSource.setCredentialsId(""); // TODO the setter ought to use fixEmpty s.setRetriever(new SCMSourceRetriever(scmSource)); s.setChangelog(true); @@ -82,18 +102,19 @@ public class LibraryStepTest { assertEquals("library identifier: 'foo@master', retriever: modernSCM(gitSource(traits: [gitBranchDiscovery()], credentialsId: '', remote: 'https://nowhere.net/'))", Snippetizer.object2Groovy(s)); s.setRetriever(new SCMRetriever(new GitSCM(Collections.singletonList(new UserRemoteConfig("https://nowhere.net/", null, null, null)), Collections.singletonList(new BranchSpec("${library.foo.version}")), - null, null, Collections.emptyList()))); + null, null, Collections.emptyList()))); s.setChangelog(false); r.assertEqualDataBoundBeans(s, stepTester.configRoundTrip(s)); snippetizerTester.assertRoundTrip(s, "library changelog: false, identifier: 'foo@master', retriever: legacySCM(scmGit(branches: [[name: '${library.foo.version}']], extensions: [], userRemoteConfigs: [[url: 'https://nowhere.net/']]))"); } - @Test public void vars() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/x.groovy", "def call() {echo 'ran library'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + @Test + void vars() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/x.groovy", "def call() {echo 'ran library'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("library 'stuff@master'; x()", true)); WorkflowRun b = r.buildAndAssertSuccess(p); @@ -102,7 +123,7 @@ public class LibraryStepTest { assertNotNull(action); String directoryName = LibraryRecord.directoryNameFor("stuff", "master", String.valueOf(true), GlobalLibraries.ForJob.class.getName()); assertEquals("[LibraryRecord{name=stuff, version=master, variables=[x], trusted=true, changelog=true, cachingConfiguration=null, directoryName=" + directoryName + "}]", action.getLibraries().toString()); - p.setDefinition(new CpsFlowDefinition("library identifier: 'otherstuff@master', retriever: modernSCM([$class: 'GitSCMSource', remote: $/" + sampleRepo + "/$, credentialsId: '']), changelog: false; x()", true)); + p.setDefinition(new CpsFlowDefinition("library identifier: 'otherstuff@master', retriever: modernSCM([$class: 'GitSCMSource', remote: $/" + sampleRepo1 + "/$, credentialsId: '']), changelog: false; x()", true)); b = r.buildAndAssertSuccess(p); r.assertLogContains("ran library", b); action = b.getAction(LibrariesAction.class); @@ -111,48 +132,55 @@ public class LibraryStepTest { assertEquals("[LibraryRecord{name=otherstuff, version=master, variables=[x], trusted=false, changelog=false, cachingConfiguration=null, directoryName=" + directoryName + "}]", action.getLibraries().toString()); } - @Test public void classes() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/some/pkg/Lib.groovy", "package some.pkg; class Lib {static class Inner {static String stuff() {Constants.CONST}}}"); - sampleRepo.write("src/some/pkg/Constants.groovy", "package some.pkg; class Constants {static String CONST = 'constant'}"); - sampleRepo.write("src/some/pkg/App.groovy", "package some.pkg; class App implements Serializable {def run() {Lib.Inner.stuff()}}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + @Test + void classes() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/some/pkg/Lib.groovy", "package some.pkg; class Lib {static class Inner {static String stuff() {Constants.CONST}}}"); + sampleRepo1.write("src/some/pkg/Constants.groovy", "package some.pkg; class Constants {static String CONST = 'constant'}"); + sampleRepo1.write("src/some/pkg/App.groovy", "package some.pkg; class App implements Serializable {def run() {Lib.Inner.stuff()}}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("def lib = library 'stuff@master'; echo(/using ${lib.some.pkg.Lib.Inner.stuff()} vs. ${lib.some.pkg.App.new().run()}/)", true)); WorkflowRun b = r.buildAndAssertSuccess(p); r.assertLogContains("using constant vs. constant", b); } - @Test public void missingProperty() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void missingProperty() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); Folder f = r.jenkins.createProject(Folder.class, "f"); - f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true)))))); WorkflowJob p = f.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "def lib = library 'stuff@master'\n" + - "lib.some.pkg.MyClass.no_field_with_this_name\n" , true)); + """ + def lib = library 'stuff@master' + lib.some.pkg.MyClass.no_field_with_this_name + """, true)); WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); r.assertLogContains("MissingPropertyException: No such property: no_field_with_this_name for class: some.pkg.MyClass", b); } - @Test public void reflectionInLoadedClassesIsIntercepted() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/some/pkg/MyThread.groovy", "package some.pkg; class MyThread extends Thread { }"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void reflectionInLoadedClassesIsIntercepted() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/some/pkg/MyThread.groovy", "package some.pkg; class MyThread extends Thread { }"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); Folder f = r.jenkins.createProject(Folder.class, "f"); - f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true)))))); WorkflowJob p = f.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "def lib = library 'stuff@master'\n" + - "catchError() { lib.some.pkg.MyThread.new(null) }\n" + - "catchError() { lib.some.pkg.MyThread.__$stMC }\n" + - "catchError() { lib.some.pkg.MyThread.$getCallSiteArray() }\n" , true)); + """ + def lib = library 'stuff@master' + catchError() { lib.some.pkg.MyThread.new(null) } + catchError() { lib.some.pkg.MyThread.__$stMC } + catchError() { lib.some.pkg.MyThread.$getCallSiteArray() } + """, true)); WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); r.assertLogContains("Rejecting illegal call to synthetic constructor", b); r.assertLogContains("staticField some.pkg.MyThread __$stMC", b); @@ -160,75 +188,89 @@ public class LibraryStepTest { } @Issue("SECURITY-2824") - @Test public void constructorInvocationInLoadedClassesIsIntercepted() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Superclass.groovy", - "package pkg;\n" + - "class Superclass { Superclass(String x) { } }\n"); - sampleRepo.write("src/pkg/Subclass.groovy", - "package pkg;\n" + - "class Subclass extends Superclass {\n" + - " def wrapper\n" + - " Subclass() { super('secret.key'); def $cw = $cw; wrapper = $cw }\n" + - "}\n"); - sampleRepo.write("src/pkg/MyFile.groovy", - "package pkg;\n" + - "class MyFile extends File {\n" + - " MyFile(String path) {\n" + - " super(path)\n" + - " }\n" + - "}\n"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void constructorInvocationInLoadedClassesIsIntercepted() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Superclass.groovy", + """ + package pkg; + class Superclass { Superclass(String x) { } } + """); + sampleRepo1.write("src/pkg/Subclass.groovy", + """ + package pkg; + class Subclass extends Superclass { + def wrapper + Subclass() { super('secret.key'); def $cw = $cw; wrapper = $cw } + } + """); + sampleRepo1.write("src/pkg/MyFile.groovy", + """ + package pkg; + class MyFile extends File { + MyFile(String path) { + super(path) + } + } + """); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); Folder f = r.jenkins.createProject(Folder.class, "f"); - f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true)))))); WorkflowJob p = f.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "def lib = library 'stuff@master'\n" + - "def wrapper = lib.pkg.Subclass.new().wrapper\n" + - "def file = lib.pkg.MyFile.new(wrapper, 'unused')\n" + - "echo(/${[file, file.class]}/)", true)); + """ + def lib = library 'stuff@master' + def wrapper = lib.pkg.Subclass.new().wrapper + def file = lib.pkg.MyFile.new(wrapper, 'unused') + echo(/${[file, file.class]}/)""", true)); WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); r.assertLogContains("Rejecting illegal call to synthetic constructor: private pkg.MyFile", b); } - @Ignore("Trusted libraries should never get a RejectedAccessException, but this case should be uncommon and is difficult to handle more precisely") - @Test public void falsePositiveRejectedAccessExceptionInTrustedLibrary() throws Exception { - sampleRepo.init(); - sampleRepo.git("branch", "myBranch"); - sampleRepo.write("vars/doStuff.groovy", - "def call() {\n" + - " def lib = library('stuff2@myBranch')\n" + - " lib.some.pkg.MyClass.$getCallSiteArray()\n" + - "}\n"); - sampleRepo.git("add", "."); - sampleRepo.git("commit", "--message=init"); - sampleRepo.git("checkout", "myBranch"); - sampleRepo.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); - sampleRepo.git("add", "."); - sampleRepo.git("commit", "--message=myBranch"); + @Disabled("Trusted libraries should never get a RejectedAccessException, but this case should be uncommon and is difficult to handle more precisely") + @Test + void falsePositiveRejectedAccessExceptionInTrustedLibrary() throws Exception { + sampleRepo1.init(); + sampleRepo1.git("branch", "myBranch"); + sampleRepo1.write("vars/doStuff.groovy", + """ + def call() { + def lib = library('stuff2@myBranch') + lib.some.pkg.MyClass.$getCallSiteArray() + } + """); + sampleRepo1.git("add", "."); + sampleRepo1.git("commit", "--message=init"); + sampleRepo1.git("checkout", "myBranch"); + sampleRepo1.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); + sampleRepo1.git("add", "."); + sampleRepo1.git("commit", "--message=myBranch"); GlobalLibraries.get().setLibraries(Arrays.asList( - new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))), - new LibraryConfiguration("stuff2", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))), + new LibraryConfiguration("stuff2", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "@Library('stuff@master')\n" + - "import doStuff\n" + - "doStuff()\n", true)); + """ + @Library('stuff@master') + import doStuff + doStuff() + """, true)); WorkflowRun b = r.buildAndAssertSuccess(p); } - @Test public void classesFromWrongPlace() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/some/pkg/Lib.groovy", "package some.pkg; class Lib {static void m() {}}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); + @Test + void classesFromWrongPlace() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/some/pkg/Lib.groovy", "package some.pkg; class Lib {static void m() {}}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); sampleRepo2.init(); sampleRepo2.write("src/other/pkg/Lib.groovy", "package other.pkg; class Lib {static void m() {}}"); sampleRepo2.git("add", "src"); sampleRepo2.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Arrays.asList( - new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))), + new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))), new LibraryConfiguration("stuph", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo2.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("library('stuff@master').some.pkg.Lib.m()", true)); @@ -246,26 +288,28 @@ public class LibraryStepTest { r.assertLogContains(IllegalAccessException.class.getName(), b); } - @Test public void callSites() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/p/C.groovy", "package p; class C {int x; C(int x) {this.x = x}; public static final String CONST = 'constant'; static String append(String x, String y) {x + y}}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("x", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + @Test + void callSites() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/p/C.groovy", "package p; class C {int x; C(int x) {this.x = x}; public static final String CONST = 'constant'; static String append(String x, String y) {x + y}}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + GlobalLibraries.get().setLibraries(Collections.singletonList(new LibraryConfiguration("x", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("def klazz = library('x@master').p.C; echo(/CONST=${klazz.CONST} x=${klazz.new(33).x} append=${klazz.append('non', null)}/)", true)); WorkflowRun b = r.buildAndAssertSuccess(p); r.assertLogContains("CONST=constant x=33 append=nonnull", b); } - @Test public void untrustedAndReplay() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/p/C.groovy", "package p; class C {static String message() {'used library'}}"); - sampleRepo.write("vars/x.groovy", "def call() {'ran library'}"); - sampleRepo.git("add", "src", "vars"); - sampleRepo.git("commit", "--message=init"); + @Test + void untrustedAndReplay() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/p/C.groovy", "package p; class C {static String message() {'used library'}}"); + sampleRepo1.write("vars/x.groovy", "def call() {'ran library'}"); + sampleRepo1.git("add", "src", "vars"); + sampleRepo1.git("commit", "--message=init"); Folder d = r.jenkins.createProject(Folder.class, "d"); - d.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); + d.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true)))))); WorkflowJob p = d.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("echo(/${library('stuff@master').p.C.message()} and ${x()}/)", true)); WorkflowRun b1 = r.buildAndAssertSuccess(p); @@ -275,19 +319,21 @@ public class LibraryStepTest { r.assertLogContains("reused library and reran library", b2); } - @Test public void nonexistentLibrary() throws Exception { + @Test + void nonexistentLibrary() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("library 'nonexistent'", true)); WorkflowRun b = r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0)); r.assertLogContains("No library named nonexistent found", b); } - @Test public void duplicatedLibrary() throws Exception { - sampleRepo.init(); - sampleRepo.write("vars/x.groovy", "def call() {echo 'ran library'}"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration cfg = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + @Test + void duplicatedLibrary() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("vars/x.groovy", "def call() {echo 'ran library'}"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration cfg = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); cfg.setDefaultVersion("master"); GlobalLibraries.get().setLibraries(Collections.singletonList(cfg)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -301,31 +347,33 @@ public class LibraryStepTest { assertEquals(1, libraries.size()); } - @Test public void usingInterpolation() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Lib.groovy", "package pkg; public class Lib {public static final String CONST = 'initial'}"); - sampleRepo.git("add", "src"); - sampleRepo.git("commit", "--message=init"); - sampleRepo.git("tag", "initial"); - sampleRepo.write("src/pkg/Lib.groovy", "package pkg; public class Lib {public static final String CONST = 'modified'}"); - sampleRepo.git("commit", "--all", "--message=modified"); + @Test + void usingInterpolation() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Lib.groovy", "package pkg; public class Lib {public static final String CONST = 'initial'}"); + sampleRepo1.git("add", "src"); + sampleRepo1.git("commit", "--message=init"); + sampleRepo1.git("tag", "initial"); + sampleRepo1.write("src/pkg/Lib.groovy", "package pkg; public class Lib {public static final String CONST = 'modified'}"); + sampleRepo1.git("commit", "--all", "--message=modified"); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - String retriever = "legacySCM([$class: 'GitSCM', branches: [[name: '${library.stuff.version}']], userRemoteConfigs: [[url: '" + sampleRepo.fileUrl() + "']]])"; + String retriever = "legacySCM([$class: 'GitSCM', branches: [[name: '${library.stuff.version}']], userRemoteConfigs: [[url: '" + sampleRepo1.fileUrl() + "']]])"; p.setDefinition(new CpsFlowDefinition("echo(/using ${library(identifier: 'stuff@master', retriever: " + retriever + ").pkg.Lib.CONST}/)", true)); r.assertLogContains("using modified", r.buildAndAssertSuccess(p)); p.setDefinition(new CpsFlowDefinition("echo(/using ${library(identifier: 'stuff@initial', retriever: " + retriever + ").pkg.Lib.CONST}/)", true)); r.assertLogContains("using initial", r.buildAndAssertSuccess(p)); } - @Test public void usingToolsFromLibrary() throws Exception { + @Test + void usingToolsFromLibrary() throws Exception { JDK.DescriptorImpl jdkDescriptor = r.jenkins.getDescriptorByType(JDK.DescriptorImpl.class); jdkDescriptor.setInstallations(new JDK("lib-java", "/lib/java"), new JDK("pipeline-java", "/pipeline/java")); - sampleRepo.init(); - sampleRepo.write("vars/x.groovy", "def call() { def path = tool 'lib-java'; echo path }"); - sampleRepo.git("add", "vars"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration cfg = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + sampleRepo1.init(); + sampleRepo1.write("vars/x.groovy", "def call() { def path = tool 'lib-java'; echo path }"); + sampleRepo1.git("add", "vars"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration cfg = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); cfg.setDefaultVersion("master"); cfg.setImplicit(true); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryTestUtils.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryTestUtils.java index aac1c676..3eb09534 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryTestUtils.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/LibraryTestUtils.java @@ -9,10 +9,11 @@ private LibraryTestUtils(){} static LibraryConfiguration defineLibraryUsingGrab(String libraryName, GitSampleRepoRule sampleRepo) throws Exception { sampleRepo.init(); sampleRepo.write("src/pkg/Wrapper.groovy", - "package pkg\n" + - "@Grab('commons-primitives:commons-primitives:1.0')\n" + - "import org.apache.commons.collections.primitives.ArrayIntList\n" + - "class Wrapper {static def list() {new ArrayIntList()}}"); + """ + package pkg + @Grab('commons-primitives:commons-primitives:1.0') + import org.apache.commons.collections.primitives.ArrayIntList + class Wrapper {static def list() {new ArrayIntList()}}"""); sampleRepo.git("add", "src"); sampleRepo.git("commit", "--message=init"); return new LibraryConfiguration(libraryName, new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString()))); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/ResourceStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/ResourceStepTest.java index 657278b1..8bc6e2bc 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/ResourceStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/ResourceStepTest.java @@ -36,41 +36,65 @@ import java.util.Arrays; import java.util.Base64; import java.util.Collections; +import java.util.List; + import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; -import static org.junit.Assume.*; -import org.junit.Test; -import org.junit.ClassRule; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import static org.junit.jupiter.api.Assumptions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +class ResourceStepTest { + + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private final GitSampleRepoRule sampleRepo1 = new GitSampleRepoRule(); + private final GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); + + @BeforeEach + void beforeEach(JenkinsRule rule) throws Throwable { + r = rule; + sampleRepo1.before(); + sampleRepo2.before(); + } -public class ResourceStepTest { - - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @Rule public GitSampleRepoRule sampleRepo2 = new GitSampleRepoRule(); + @AfterEach + void afterEach() { + sampleRepo1.after(); + sampleRepo2.after(); + } - @Test public void smokes() throws Exception { + @Test + void smokes() throws Exception { initFixedContentLibrary(); GlobalLibraries.get().setLibraries(Collections.singletonList( - new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('stuff@master') import pkg.Stuff; echo(/got ${Stuff.contents(this)}/)", true)); r.assertLogContains("got fixed contents", r.buildAndAssertSuccess(p)); } - @Test public void caching() throws Exception { + @Test + void caching() throws Exception { clearCache("stuff"); initFixedContentLibrary(); - LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); libraryConfig.setCachingConfiguration(new LibraryCachingConfiguration(0, "")); GlobalLibraries.get().setLibraries(Collections.singletonList(libraryConfig)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -87,11 +111,12 @@ public class ResourceStepTest { r.assertLogNotContains("git", secondBuild); // git is not called } - @Test public void cachingExcludedLibrary() throws Exception { + @Test + void cachingExcludedLibrary() throws Exception { clearCache("stuff"); initFixedContentLibrary(); - LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); libraryConfig.setCachingConfiguration(new LibraryCachingConfiguration(0, "test_unused other")); GlobalLibraries.get().setLibraries(Collections.singletonList(libraryConfig)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -109,11 +134,12 @@ public class ResourceStepTest { r.assertLogContains("git", secondBuild); // git is called } - @Test public void cachingRefresh() throws Exception { + @Test + void cachingRefresh() throws Exception { clearCache("stuff"); initFixedContentLibrary(); - LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + LibraryConfiguration libraryConfig = new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); libraryConfig.setCachingConfiguration(new LibraryCachingConfiguration(60, "test_unused other")); GlobalLibraries.get().setLibraries(Collections.singletonList(libraryConfig)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -138,24 +164,26 @@ public class ResourceStepTest { r.assertLogContains("git", thirdBuild); // git is called } - @Test public void missingResource() throws Exception { + @Test + void missingResource() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("libraryResource 'whatever'", true)); r.assertLogContains(Messages.ResourceStep_no_such_library_resource_could_be_found_("whatever"), r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0))); } - @Test public void duplicatedResources() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {static def contents(script) {script.libraryResource 'pkg/file'}}"); - sampleRepo.write("resources/pkg/file", "initial contents"); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); - sampleRepo.git("tag", "v1"); - sampleRepo.write("resources/pkg/file", "subsequent contents"); - sampleRepo.git("commit", "--all", "--message=edited"); - LibraryConfiguration stuff1 = new LibraryConfiguration("stuff1", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + @Test + void duplicatedResources() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {static def contents(script) {script.libraryResource 'pkg/file'}}"); + sampleRepo1.write("resources/pkg/file", "initial contents"); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); + sampleRepo1.git("tag", "v1"); + sampleRepo1.write("resources/pkg/file", "subsequent contents"); + sampleRepo1.git("commit", "--all", "--message=edited"); + LibraryConfiguration stuff1 = new LibraryConfiguration("stuff1", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); stuff1.setDefaultVersion("v1"); - LibraryConfiguration stuff2 = new LibraryConfiguration("stuff2", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))); + LibraryConfiguration stuff2 = new LibraryConfiguration("stuff2", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))); stuff2.setDefaultVersion("master"); GlobalLibraries.get().setLibraries(Arrays.asList(stuff1, stuff2)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -164,22 +192,23 @@ public class ResourceStepTest { } @Issue("JENKINS-52313") - @Test public void specifyResourceEncoding() throws Exception { - assumeFalse("TODO mojibake on windows-11-2.164.1", Functions.isWindows()); - sampleRepo.init(); - sampleRepo.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {" + + @Test + void specifyResourceEncoding() throws Exception { + assumeFalse(Functions.isWindows(), "TODO mojibake on windows-11-2.164.1"); + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {" + "static def utf8(script) {script.libraryResource(resource: 'pkg/utf8', encoding: 'ISO-8859-15')}\n" + "static def binary(script) {script.libraryResource(resource: 'pkg/binary', encoding: 'Base64')}}"); - Path resourcesDir = Paths.get(sampleRepo.getRoot().getPath(), "resources", "pkg"); + Path resourcesDir = Paths.get(sampleRepo1.getRoot().getPath(), "resources", "pkg"); Files.createDirectories(resourcesDir); // '¤' encoded using ISO-8859-1 should turn into '€' when decoding using ISO-8859-15. - Files.write(resourcesDir.resolve("utf8"), Arrays.asList("¤"), StandardCharsets.ISO_8859_1); + Files.write(resourcesDir.resolve("utf8"), List.of("¤"), StandardCharsets.ISO_8859_1); byte[] binaryData = {0x48, 0x45, 0x4c, 0x4c, 0x4f, (byte) 0x80, (byte) 0xec, (byte) 0xf4, 0x00, 0x0d, 0x1b}; Files.write(resourcesDir.resolve("binary"), binaryData); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); GlobalLibraries.get().setLibraries(Collections.singletonList( - new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); + new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo1.toString(), "", "*", "", true))))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition("@Library('stuff@master') import pkg.Stuff; echo(Stuff.utf8(this)); echo(Stuff.binary(this))", true)); Run run = r.buildAndAssertSuccess(p); @@ -188,18 +217,19 @@ public class ResourceStepTest { } @Issue("SECURITY-2479") - @Test public void symlinksInLibraryResourcesAreNotAllowedToEscapeWorkspaceContext() throws Exception { + @Test + void symlinksInLibraryResourcesAreNotAllowedToEscapeWorkspaceContext() throws Exception { assumeFalse(Functions.isWindows()); // On Windows, the symlink is treated as a regular file, so there is no vulnerability, but the behavior is different. - sampleRepo.init(); - sampleRepo.write("src/Stuff.groovy", "class Stuff {static def contents(script) {script.libraryResource 'master.key'}}"); - Path resourcesDir = Paths.get(sampleRepo.getRoot().getPath(), "resources"); + sampleRepo1.init(); + sampleRepo1.write("src/Stuff.groovy", "class Stuff {static def contents(script) {script.libraryResource 'master.key'}}"); + Path resourcesDir = Paths.get(sampleRepo1.getRoot().getPath(), "resources"); Files.createDirectories(resourcesDir); Path symlinkPath = Paths.get(resourcesDir.toString(), "master.key"); Files.createSymbolicLink(symlinkPath, Paths.get("../../../../../../../secrets/master.key")); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration libraryConfiguration = new LibraryConfiguration("symlink-stuff", new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString()))); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration libraryConfiguration = new LibraryConfiguration("symlink-stuff", new SCMSourceRetriever(new GitSCMSource(sampleRepo1.toString()))); GlobalLibraries.get().setLibraries(Collections.singletonList(libraryConfiguration)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -208,15 +238,16 @@ public class ResourceStepTest { } @Issue("SECURITY-2476") - @Test public void libraryResourceNotAllowedToEscapeWorkspaceContext() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/Stuff.groovy", "class Stuff {static def contents(script) {script.libraryResource '../../../../../../../secrets/master.key'}}"); - Path resourcesDir = Paths.get(sampleRepo.getRoot().getPath(), "resources"); + @Test + void libraryResourceNotAllowedToEscapeWorkspaceContext() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/Stuff.groovy", "class Stuff {static def contents(script) {script.libraryResource '../../../../../../../secrets/master.key'}}"); + Path resourcesDir = Paths.get(sampleRepo1.getRoot().getPath(), "resources"); Files.createDirectories(resourcesDir); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); - LibraryConfiguration libraryConfiguration = new LibraryConfiguration("libres-stuff", new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString()))); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); + LibraryConfiguration libraryConfiguration = new LibraryConfiguration("libres-stuff", new SCMSourceRetriever(new GitSCMSource(sampleRepo1.toString()))); GlobalLibraries.get().setLibraries(Collections.singletonList(libraryConfiguration)); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -225,12 +256,13 @@ public class ResourceStepTest { r.assertLogContains("../../../../../../../secrets/master.key references a file that is not contained within the library: libres-stuff", r.buildAndAssertStatus(Result.FAILURE, p)); } - @Test public void findResourcesAttemptsToLoadFromAllIncludedLibraries() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/Stuff.groovy", ""); - sampleRepo.write("resources/foo.txt", "Hello from foo!"); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); + @Test + void findResourcesAttemptsToLoadFromAllIncludedLibraries() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/Stuff.groovy", ""); + sampleRepo1.write("resources/foo.txt", "Hello from foo!"); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); sampleRepo2.init(); sampleRepo2.write("src/Thing.groovy", ""); @@ -239,7 +271,7 @@ public class ResourceStepTest { sampleRepo2.git("commit", "--message=init"); LibraryConfiguration libraryConfiguration = new LibraryConfiguration("stuff", - new SCMSourceRetriever(new GitSCMSource(sampleRepo.toString()))); + new SCMSourceRetriever(new GitSCMSource(sampleRepo1.toString()))); LibraryConfiguration libraryConfiguration2 = new LibraryConfiguration("thing", new SCMSourceRetriever(new GitSCMSource(sampleRepo2.toString()))); GlobalLibraries.get().setLibraries(Arrays.asList(libraryConfiguration, libraryConfiguration2)); @@ -253,23 +285,23 @@ public class ResourceStepTest { r.assertLogContains("Hello from foo!", run); } - public void initFixedContentLibrary() throws Exception { - sampleRepo.init(); - sampleRepo.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {static def contents(script) {script.libraryResource 'pkg/file'}}"); - sampleRepo.write("resources/pkg/file", "fixed contents"); - sampleRepo.git("add", "src", "resources"); - sampleRepo.git("commit", "--message=init"); - sampleRepo.git("branch", "other"); + private void initFixedContentLibrary() throws Exception { + sampleRepo1.init(); + sampleRepo1.write("src/pkg/Stuff.groovy", "package pkg; class Stuff {static def contents(script) {script.libraryResource 'pkg/file'}}"); + sampleRepo1.write("resources/pkg/file", "fixed contents"); + sampleRepo1.git("add", "src", "resources"); + sampleRepo1.git("commit", "--message=init"); + sampleRepo1.git("branch", "other"); } - public void clearCache(String name) throws Exception { + private void clearCache(String name) throws Exception { FilePath cacheDir = new FilePath(LibraryCachingConfiguration.getGlobalLibrariesCacheDir(), name); if (cacheDir.exists()) { cacheDir.deleteRecursive(); } } - public void modifyCacheTimestamp(String name, String version, long timestamp) throws Exception { + private void modifyCacheTimestamp(String name, String version, long timestamp) throws Exception { String cacheDirName = LibraryRecord.directoryNameFor(name, version, String.valueOf(true), GlobalLibraries.ForJob.class.getName()); FilePath cacheDir = new FilePath(LibraryCachingConfiguration.getGlobalLibrariesCacheDir(), cacheDirName); if (cacheDir.exists()) { diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/RestartTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/RestartTest.java index 670c83a1..5d9cce3f 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/RestartTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/RestartTest.java @@ -31,27 +31,40 @@ import java.util.concurrent.atomic.AtomicLong; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.ClassRule; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsSessionRule; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension; -public class RestartTest { +@WithGitSampleRepo +class RestartTest { - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsSessionRule rr = new JenkinsSessionRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + @RegisterExtension + private final JenkinsSessionExtension extension = new JenkinsSessionExtension(); + private GitSampleRepoRule sampleRepo; + + @BeforeEach + void beforeEach(GitSampleRepoRule repo) { + sampleRepo = repo; + } - @Test public void smokes() throws Throwable { - rr.then(j -> { + @Test + void smokes() throws Throwable { + extension.then(j -> { sampleRepo.init(); sampleRepo.write("src/pkg/Slow.groovy", "package pkg; class Slow {static void wait(script) {script.semaphore 'wait-class'}}"); sampleRepo.write("vars/slow.groovy", "def call() {semaphore 'wait-var'}"); @@ -63,13 +76,13 @@ public class RestartTest { WorkflowRun b = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait-class/1", b); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait-class/1", null); SemaphoreStep.waitForStart("wait-var/1", b); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait-var/1", null); @@ -78,9 +91,10 @@ public class RestartTest { }); } - @Test public void replay() throws Throwable { + @Test + void replay() throws Throwable { final String initialScript = "def call() {semaphore 'wait'; echo 'initial content'}"; - rr.then(j -> { + extension.then(j -> { sampleRepo.init(); sampleRepo.write("vars/slow.groovy", initialScript); sampleRepo.git("add", "vars"); @@ -93,7 +107,7 @@ public class RestartTest { WorkflowRun b1 = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("wait/1", b1); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("d/p", WorkflowJob.class); WorkflowRun b1 = p.getLastBuild(); SemaphoreStep.success("wait/1", null); @@ -103,7 +117,7 @@ public class RestartTest { WorkflowRun b2 = (WorkflowRun) ra.run(ra.getOriginalScript(), Collections.singletonMap("slow", initialScript.replace("initial", "subsequent"))).waitForStart(); SemaphoreStep.waitForStart("wait/2", b2); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("d/p", WorkflowJob.class); WorkflowRun b2 = p.getLastBuild(); SemaphoreStep.success("wait/2", null); @@ -112,8 +126,9 @@ public class RestartTest { } @Issue("JENKINS-39719") - @Test public void syntheticMethodOverride() throws Throwable { - rr.then(j -> { + @Test + void syntheticMethodOverride() throws Throwable { + extension.then(j -> { sampleRepo.init(); sampleRepo.write("src/p/MyTest.groovy", "package p; class MyTest {def mytest1() {}}"); sampleRepo.write("src/p/MyOtherTest.groovy", "package p; class MyOtherTest {def test1() {}; def test2() {}}"); @@ -131,7 +146,7 @@ public class RestartTest { SemaphoreStep.waitForStart("wait/1", p.scheduleBuild2(0).waitForStart()); ((AtomicLong) f.get(null)).set(0); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b2 = p.getLastBuild(); assertEquals(2, b2.getNumber()); @@ -140,8 +155,9 @@ public class RestartTest { }); } - @Test public void step() throws Throwable { - rr.then(j -> { + @Test + void step() throws Throwable { + extension.then(j -> { sampleRepo.init(); sampleRepo.write("src/pkg/Slow.groovy", "package pkg; class Slow {static void wait(script) {script.semaphore 'wait-class'}}"); sampleRepo.write("vars/slow.groovy", "def call() {semaphore 'wait-var'}"); @@ -153,19 +169,19 @@ public class RestartTest { WorkflowRun b = p.scheduleBuild2(0).waitForStart(); SemaphoreStep.waitForStart("start/1", b); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("start/1", null); SemaphoreStep.waitForStart("wait-class/1", b); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait-class/1", null); SemaphoreStep.waitForStart("wait-var/1", b); }); - rr.then(j -> { + extension.then(j -> { WorkflowJob p = j.jenkins.getItemByFullName("p", WorkflowJob.class); WorkflowRun b = p.getLastBuild(); SemaphoreStep.success("wait-var/1", null); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMRetrieverTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMRetrieverTest.java index d0fbbff7..6faf97ac 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMRetrieverTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMRetrieverTest.java @@ -30,8 +30,10 @@ import hudson.model.Result; import hudson.model.TaskListener; import jenkins.branch.BranchSource; +import jenkins.model.Jenkins; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import jenkins.plugins.git.traits.BranchDiscoveryTrait; import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMRevision; @@ -41,27 +43,37 @@ import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject; import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectTest; import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.Rule; -import org.jvnet.hudson.test.BuildWatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.Url; +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +@WithGitSampleRepo +class SCMRetrieverTest { -public class SCMRetrieverTest { + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) throws Exception { + r = rule; + sampleRepo = repo; - @Before public void doNotWait() { - r.setQuietPeriod(0); + Jenkins.get().setQuietPeriod(0); } @Url("https://stackoverflow.com/a/49112612/12916") - @Test public void selfTestLibraries() throws Exception { + @Test + void selfTestLibraries() throws Exception { sampleRepo.init(); sampleRepo.write("vars/greet.groovy", "def call(recipient) {echo(/hello to $recipient/)}"); sampleRepo.write("src/pkg/Clazz.groovy", "package pkg; class Clazz {static String whereAmI() {'earth'}}"); @@ -103,7 +115,8 @@ public class SCMRetrieverTest { } @Issue("SECURITY-1951") - @Test public void untrustedUsersCanOverideLibraryWithOtherSource() throws Exception { + @Test + void untrustedUsersCanOverrideLibraryWithOtherSource() throws Exception { sampleRepo.init(); sampleRepo.write("vars/greet.groovy", "def call(recipient) {echo(/hello to $recipient/)}"); sampleRepo.write("src/pkg/Clazz.groovy", "package pkg; class Clazz {static String whereAmI() {'master'}}"); @@ -129,7 +142,8 @@ public class SCMRetrieverTest { r.assertLogContains("Library '" + libraryName + "' has been modified in an untrusted revision", run); } - @Test public void libraryCanBeRetrievedStaticallyEvenWhenPipelineScmUntrusted() throws Exception { + @Test + void libraryCanBeRetrievedStaticallyEvenWhenPipelineScmUntrusted() throws Exception { sampleRepo.init(); sampleRepo.write("vars/greet.groovy", "def call(recipient) {echo(/hello from $recipient/)}"); sampleRepo.write("src/pkg/Clazz.groovy", "package pkg; class Clazz {static String whereAmI() {'master'}}"); @@ -159,7 +173,8 @@ public class SCMRetrieverTest { } @Issue("SECURITY-1951") - @Test public void libraryCantBeRetrievedWithoutVersionUsingScmSourceRetriever() throws Exception { + @Test + void libraryCantBeRetrievedWithoutVersionUsingScmSourceRetriever() throws Exception { sampleRepo.init(); sampleRepo.write("vars/greet.groovy", "def call(recipient) {echo(/hello to $recipient/)}"); sampleRepo.write("src/pkg/Clazz.groovy", "package pkg; class Clazz {static String whereAmI() {'master'}}"); @@ -190,6 +205,7 @@ public static class WarySource extends GitSCMSource { public WarySource(String remote) { super(null, remote, "", "*", "", false); } + @Override @NonNull public SCMRevision getTrustedRevision(@NonNull SCMRevision revision, @NonNull TaskListener listener) throws IOException, InterruptedException { @@ -202,5 +218,4 @@ public SCMRevision getTrustedRevision(@NonNull SCMRevision revision, @NonNull Ta } } } - } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMSourceRetrieverTest.java b/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMSourceRetrieverTest.java index f8c8110a..c4d3351c 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMSourceRetrieverTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/libs/SCMSourceRetrieverTest.java @@ -41,6 +41,7 @@ import java.util.logging.Level; import jenkins.plugins.git.GitSCMSource; import jenkins.plugins.git.GitSampleRepoRule; +import jenkins.plugins.git.junit.jupiter.WithGitSampleRepo; import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMHeadEvent; import jenkins.scm.api.SCMHeadObserver; @@ -56,18 +57,21 @@ import hudson.plugins.git.extensions.impl.CloneOption; import jenkins.plugins.git.traits.CloneOptionTrait; import jenkins.plugins.git.traits.RefSpecsSCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTrait; + import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.*; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.BuildWatcher; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.extension.RegisterExtension; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.LogRecorder; import org.jvnet.hudson.test.SingleFileSCM; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.WithoutJenkins; @@ -78,19 +82,39 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.matchesPattern; import static org.jenkinsci.plugins.workflow.libs.SCMBasedRetriever.PROHIBITED_DOUBLE_DOT; -import org.jvnet.hudson.test.FlagRule; -import org.jvnet.hudson.test.LoggerRule; -public class SCMSourceRetrieverTest { +import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +@WithJenkins +@WithGitSampleRepo +class SCMSourceRetrieverTest { - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - @Rule public JenkinsRule r = new JenkinsRule(); - @Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule(); - @Rule public FlagRule includeSrcTest = new FlagRule<>(() -> SCMBasedRetriever.INCLUDE_SRC_TEST_IN_LIBRARIES, v -> SCMBasedRetriever.INCLUDE_SRC_TEST_IN_LIBRARIES = v); - @Rule public LoggerRule logging = new LoggerRule().record(SCMBasedRetriever.class, Level.FINE); + @SuppressWarnings("unused") + @RegisterExtension + private static final BuildWatcherExtension BUILD_WATCHER = new BuildWatcherExtension(); + private JenkinsRule r; + private GitSampleRepoRule sampleRepo; + + private boolean includeSrcTest; + private final LogRecorder logging = new LogRecorder().record(SCMBasedRetriever.class, Level.FINE); + + @BeforeEach + void beforeEach(JenkinsRule rule, GitSampleRepoRule repo) { + r = rule; + sampleRepo = repo; + + includeSrcTest = SCMBasedRetriever.INCLUDE_SRC_TEST_IN_LIBRARIES; + } + + @AfterEach + void afterEach() { + SCMBasedRetriever.INCLUDE_SRC_TEST_IN_LIBRARIES = includeSrcTest; + } @Issue("JENKINS-40408") - @Test public void lease() throws Exception { + @Test + void lease() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "vars"); @@ -114,7 +138,8 @@ public class SCMSourceRetrieverTest { } @Issue("JENKINS-41497") - @Test public void includeChanges() throws Exception { + @Test + void includeChanges() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "vars"); @@ -148,7 +173,8 @@ public class SCMSourceRetrieverTest { } @Issue("JENKINS-41497") - @Test public void dontIncludeChanges() throws Exception { + @Test + void dontIncludeChanges() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "vars"); @@ -174,7 +200,8 @@ public class SCMSourceRetrieverTest { } @Issue("JENKINS-38609") - @Test public void libraryPath() throws Exception { + @Test + void libraryPath() throws Exception { sampleRepo.init(); sampleRepo.write("sub/path/vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "sub"); @@ -191,7 +218,8 @@ public class SCMSourceRetrieverTest { } @Issue("JENKINS-38609") - @Test public void libraryPathSecurity() throws Exception { + @Test + void libraryPathSecurity() throws Exception { sampleRepo.init(); sampleRepo.write("sub/path/vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "sub"); @@ -208,7 +236,8 @@ public class SCMSourceRetrieverTest { } @WithoutJenkins - @Test public void libraryPathMatcher() { + @Test + void libraryPathMatcher() { assertThat("..", matchesPattern(PROHIBITED_DOUBLE_DOT)); assertThat("./..", matchesPattern(PROHIBITED_DOUBLE_DOT)); assertThat("../foo", matchesPattern(PROHIBITED_DOUBLE_DOT)); @@ -219,7 +248,8 @@ public class SCMSourceRetrieverTest { } @Issue("JENKINS-43802") - @Test public void owner() throws Exception { + @Test + void owner() throws Exception { GlobalLibraries.get().setLibraries(Collections.singletonList( new LibraryConfiguration("test", new SCMSourceRetriever(new NeedsOwnerSCMSource())))); WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); @@ -228,8 +258,11 @@ public class SCMSourceRetrieverTest { r.assertLogContains("loaded lib #abc123", b); r.assertLogContains("Running in retrieve from p", b); } + public static final class NeedsOwnerSCMSource extends SCMSource { - @Override protected SCMRevision retrieve(String version, TaskListener listener, Item context) throws IOException, InterruptedException { + + @Override + protected SCMRevision retrieve(String version, TaskListener listener, Item context) throws IOException, InterruptedException { if (context == null) { throw new AbortException("No context in retrieve!"); } else { @@ -237,36 +270,50 @@ public static final class NeedsOwnerSCMSource extends SCMSource { } return new DummySCMRevision(version, new SCMHead("trunk")); } - @Override public SCM build(SCMHead head, SCMRevision revision) { + + @Override + public SCM build(SCMHead head, SCMRevision revision) { String version = ((DummySCMRevision) revision).version; return new SingleFileSCM("vars/libVersion.groovy", ("def call() {'" + version + "'}").getBytes()); } + private static final class DummySCMRevision extends SCMRevision { private final String version; + DummySCMRevision(String version, SCMHead head) { super(head); this.version = version; } - @Override public boolean equals(Object obj) { + + @Override + public boolean equals(Object obj) { return obj instanceof DummySCMRevision && version.equals(((DummySCMRevision) obj).version); } - @Override public int hashCode() { + + @Override + public int hashCode() { return version.hashCode(); } } - @Override protected void retrieve(SCMSourceCriteria criteria, SCMHeadObserver observer, SCMHeadEvent event, TaskListener listener) throws IOException, InterruptedException { + + @Override + protected void retrieve(SCMSourceCriteria criteria, SCMHeadObserver observer, SCMHeadEvent event, TaskListener listener) throws IOException, InterruptedException { throw new IOException("not implemented"); } - @TestExtension("owner") public static final class DescriptorImpl extends SCMSourceDescriptor {} + + @TestExtension("owner") + public static final class DescriptorImpl extends SCMSourceDescriptor {} } - @Test public void retry() throws Exception { + @Test + void retry() throws Exception { WorkflowRun b = prepareRetryTests(new FailingSCMSource()); r.assertLogContains("Failing 'checkout' on purpose!", b); r.assertLogContains("Retrying after 10 seconds", b); } - @Test public void retryDuringFetch() throws Exception { + @Test + void retryDuringFetch() throws Exception { WorkflowRun b = prepareRetryTests(new FailingSCMSourceDuringFetch()); r.assertLogContains("Failing 'fetch' on purpose!", b); r.assertLogContains("Retrying after 10 seconds", b); @@ -287,44 +334,66 @@ private WorkflowRun prepareRetryTests(SCMSource scmSource) throws Exception{ } @Test - public void modernAndLegacyImpls() { + void modernAndLegacyImpls() { SCMSourceRetriever.DescriptorImpl modern = lookupSingleton(SCMSourceRetriever.DescriptorImpl.class); containsInAnyOrder(modern.getSCMDescriptors(), contains(instanceOf(FakeModernSCM.DescriptorImpl.class))); containsInAnyOrder(modern.getSCMDescriptors(), contains(instanceOf(FakeAlsoModernSCM.DescriptorImpl.class))); containsInAnyOrder(modern.getSCMDescriptors(), not(contains(instanceOf(BasicSCMSource.DescriptorImpl.class)))); } + // Implementation of latest and greatest API public static final class FakeModernSCM extends SCMSource { - @Override protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} - @Override public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } - @TestExtension("modernAndLegacyImpls") public static final class DescriptorImpl extends SCMSourceDescriptor {} + + @Override + protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} + + @Override + public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } + + @TestExtension("modernAndLegacyImpls") + public static final class DescriptorImpl extends SCMSourceDescriptor {} @Override protected SCMRevision retrieve(@NonNull String thingName, @NonNull TaskListener listener, Item context) throws IOException, InterruptedException { return super.retrieve(thingName, listener, context); } } + // Implementation of second latest and second greatest API public static final class FakeAlsoModernSCM extends SCMSource { - @Override protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} - @Override public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } - @TestExtension("modernAndLegacyImpls") public static final class DescriptorImpl extends SCMSourceDescriptor {} + + @Override + protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} + + @Override + public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } + + @TestExtension("modernAndLegacyImpls") + public static final class DescriptorImpl extends SCMSourceDescriptor {} @Override protected SCMRevision retrieve(@NonNull String thingName, @NonNull TaskListener listener) throws IOException, InterruptedException { return super.retrieve(thingName, listener); } } + // No modern stuff public static class BasicSCMSource extends SCMSource { - @Override protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} - @Override public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } - @TestExtension("modernAndLegacyImpls") public static final class DescriptorImpl extends SCMSourceDescriptor {} + + @Override + protected void retrieve(SCMSourceCriteria c, @NonNull SCMHeadObserver o, SCMHeadEvent e, @NonNull TaskListener l) {} + + @Override + public @NonNull SCM build(@NonNull SCMHead head, SCMRevision revision) { return null; } + + @TestExtension("modernAndLegacyImpls") + public static final class DescriptorImpl extends SCMSourceDescriptor {} } @Issue("JENKINS-66629") - @Test public void renameDeletesOldLibsWorkspace() throws Exception { + @Test + void renameDeletesOldLibsWorkspace() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "vars"); @@ -348,7 +417,8 @@ public static class BasicSCMSource extends SCMSource { } @Issue("JENKINS-66629") - @Test public void deleteRemovesLibsWorkspace() throws Exception { + @Test + void deleteRemovesLibsWorkspace() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "vars"); @@ -366,7 +436,8 @@ public static class BasicSCMSource extends SCMSource { assertFalse(ws.exists()); } - @Test public void cloneMode() throws Exception { + @Test + void cloneMode() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.write("README.md", "Summary"); @@ -376,7 +447,7 @@ public static class BasicSCMSource extends SCMSource { GitSCMSource src = new GitSCMSource(sampleRepo.toString()); CloneOption cloneOption = new CloneOption(true, true, null, null); cloneOption.setHonorRefspec(true); - src.setTraits(List.of(new CloneOptionTrait(cloneOption), new RefSpecsSCMSourceTrait("+refs/heads/master:refs/remotes/origin/master"))); + src.setTraits(List.of(new CloneOptionTrait(cloneOption), new RefSpecsSCMSourceTrait("+refs/heads/master:refs/remotes/origin/master"))); SCMSourceRetriever scm = new SCMSourceRetriever(src); LibraryConfiguration lc = new LibraryConfiguration("echoing", scm); lc.setIncludeInChangesets(false); @@ -396,7 +467,8 @@ public static class BasicSCMSource extends SCMSource { assertThat(entries, arrayContainingInAnyOrder("vars")); } - @Test public void cloneModeLibraryPath() throws Exception { + @Test + void cloneModeLibraryPath() throws Exception { sampleRepo.init(); sampleRepo.write("sub/path/vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "sub"); @@ -417,7 +489,8 @@ public static class BasicSCMSource extends SCMSource { assertThat(entries, arrayContainingInAnyOrder("vars")); } - @Test public void cloneModeLibraryPathSecurity() throws Exception { + @Test + void cloneModeLibraryPathSecurity() throws Exception { sampleRepo.init(); sampleRepo.write("sub/path/vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.git("add", "sub"); @@ -434,7 +507,8 @@ public static class BasicSCMSource extends SCMSource { r.assertLogContains("Library path may not contain '..'", b); } - @Test public void cloneModeExcludeSrcTest() throws Exception { + @Test + void cloneModeExcludeSrcTest() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); sampleRepo.write("src/test/X.groovy", "// irrelevant"); @@ -455,7 +529,8 @@ public static class BasicSCMSource extends SCMSource { r.assertLogContains("Excluding src/test/ from checkout", b); } - @Test public void cloneModeIncludeSrcTest() throws Exception { + @Test + void cloneModeIncludeSrcTest() throws Exception { sampleRepo.init(); sampleRepo.write("vars/myecho.groovy", "def call() {echo(/got ${new test.X().m()}/)}"); sampleRepo.write("src/test/X.groovy", "package test; class X {def m() {'something special'}}"); @@ -475,5 +550,4 @@ public static class BasicSCMSource extends SCMSource { r.assertLogContains("got something special", b); r.assertLogNotContains("Excluding src/test/ from checkout", b); } - }