From 1efbe87e83d1db24ae8b23b190988c6cbe32afd6 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 26 Apr 2019 10:49:44 -0500 Subject: [PATCH 01/59] Add Hamcrest matchers for Secret and Pattern Signed-off-by: Matt Sicker --- .../jvnet/hudson/test/JenkinsMatchers.java | 57 +++++++++++++++++++ .../hudson/test/JenkinsMatchersTest.java | 30 ++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/test/java/org/jvnet/hudson/test/JenkinsMatchersTest.java diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java b/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java index b73efc218..672e9d576 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java @@ -1,14 +1,18 @@ package org.jvnet.hudson.test; import hudson.util.FormValidation; +import hudson.util.Secret; import org.hamcrest.BaseMatcher; import org.hamcrest.CoreMatchers; import org.hamcrest.Description; +import org.hamcrest.FeatureMatcher; import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; +import java.util.regex.Pattern; /** * Some handy matchers. @@ -393,4 +397,57 @@ public void describeTo(Description description) { } } + /** + * Returns a Matcher for the plain text value of a Secret. + * @since TODO + */ + public static Matcher hasPlainText(Matcher matcher) { + return new HasPlainText(matcher); + } + + /** + * Returns a Matcher for the plain text value of a Secret. + * @since TODO + */ + public static Matcher hasPlainText(String expected) { + return new HasPlainText(CoreMatchers.equalTo(expected)); + } + + private static class HasPlainText extends FeatureMatcher { + private HasPlainText(Matcher matcher) { + super(matcher, "has plain text", "has plain text"); + } + + @Override + protected String featureValueOf(Secret actual) { + return actual.getPlainText(); + } + } + + /** + * Returns a Matcher that matches against the given pattern using {@link java.util.regex.Matcher#find()}. + * @since TODO + */ + public static Matcher matchesPattern(String pattern) { + return new MatchesPattern(Pattern.compile(pattern)); + } + + private static class MatchesPattern extends TypeSafeMatcher { + private final Pattern pattern; + + private MatchesPattern(Pattern pattern) { + this.pattern = pattern; + } + + @Override + protected boolean matchesSafely(String item) { + return pattern.matcher(item).find(); + } + + @Override + public void describeTo(Description description) { + description.appendText("matches pattern ").appendText(pattern.pattern()); + } + } + } diff --git a/src/test/java/org/jvnet/hudson/test/JenkinsMatchersTest.java b/src/test/java/org/jvnet/hudson/test/JenkinsMatchersTest.java new file mode 100644 index 000000000..56d38752c --- /dev/null +++ b/src/test/java/org/jvnet/hudson/test/JenkinsMatchersTest.java @@ -0,0 +1,30 @@ +package org.jvnet.hudson.test; + +import hudson.util.Secret; +import org.junit.Test; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; +import static org.jvnet.hudson.test.JenkinsMatchers.hasPlainText; +import static org.jvnet.hudson.test.JenkinsMatchers.matchesPattern; + +public class JenkinsMatchersTest { + + @Test + public void testHasPlainText() { + String plaintext = UUID.randomUUID().toString(); + Secret secret = Secret.fromString(plaintext); + assertThat(secret, hasPlainText(not(isEmptyOrNullString()))); + assertThat(secret, hasPlainText(matchesPattern("[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"))); + } + + @Test + public void testMatchesPattern() { + int value = ThreadLocalRandom.current().nextInt(42); + assertThat(String.valueOf(value), matchesPattern("\\d+")); + } +} \ No newline at end of file From 4077c7461b9f1ef8e09b5e810fb1dbdb91a00de5 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 30 Apr 2019 11:43:18 -0400 Subject: [PATCH 02/59] Incrementalified. --- .mvn/extensions.xml | 7 +++++++ .mvn/maven.config | 2 ++ pom.xml | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .mvn/extensions.xml create mode 100644 .mvn/maven.config diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 000000000..94863e605 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.0-beta-7 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 000000000..2a0299c48 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1,2 @@ +-Pconsume-incrementals +-Pmight-produce-incrementals diff --git a/pom.xml b/pom.xml index 13ebf7380..0825d86a9 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.50-SNAPSHOT + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,10 +43,12 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - HEAD + ${scmTag} + 2.50 + -SNAPSHOT UTF-8 9.4.5.v20170502 8 From 0bbec73530c8c45cf79cfa43c0f19ea6e9c89871 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 30 Apr 2019 11:46:53 -0400 Subject: [PATCH 03/59] Trying to deploy incrementals. --- Jenkinsfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0577c9353..dea718006 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,11 +13,17 @@ pipeline { stage('main') { // TODO Windows build in parallel steps { - sh 'mvn -B clean verify' + sh 'mvn -B clean verify -Dset.changelist' } post { success { junit '**/target/surefire-reports/TEST-*.xml' + dir("$HOME/.m2/repository") { + archiveArtifacts 'org/jenkins-ci/main/jenkins-test-harness/*-rc*/' + } + script { + infra.maybePublishIncrementals() + } } } } From 5db1e4dab75c46970c39a9de818adc7baf3a7498 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 29 May 2019 20:53:19 -0400 Subject: [PATCH 04/59] Always print softErr from MemoryAssert even if test ultimately passes. --- src/main/java/org/jvnet/hudson/test/MemoryAssert.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jvnet/hudson/test/MemoryAssert.java b/src/main/java/org/jvnet/hudson/test/MemoryAssert.java index 159bb63e5..46ae1143b 100644 --- a/src/main/java/org/jvnet/hudson/test/MemoryAssert.java +++ b/src/main/java/org/jvnet/hudson/test/MemoryAssert.java @@ -197,6 +197,7 @@ public static void assertGC(WeakReference reference, boolean allowSoft) { return !referent.equals(reference) || !(referredFrom instanceof WeakReference); } }) + "; apparent weak references: " + fromRoots(Collections.singleton(obj), null, null, ScannerUtils.skipObjectsFilter(Collections.singleton(reference), true)); + System.err.println(softErr); } } } From b8ee8667bab4de99e2f3b22faf6633b1b9b3b443 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 30 May 2019 09:30:58 -0400 Subject: [PATCH 05/59] As in https://github.com/stapler/stapler/pull/159, it is easier to do what we need in Scripted syntax. --- Jenkinsfile | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index dea718006..e96394142 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,31 +1,21 @@ -pipeline { - options { - buildDiscarder(logRotator(numToKeepStr: '20')) - timeout(time: 1, unit: 'HOURS') - } - agent { - docker { - image 'maven:3.5.0-jdk-8' - label 'docker' - } - } - stages { - stage('main') { - // TODO Windows build in parallel - steps { - sh 'mvn -B clean verify -Dset.changelist' - } - post { - success { - junit '**/target/surefire-reports/TEST-*.xml' - dir("$HOME/.m2/repository") { - archiveArtifacts 'org/jenkins-ci/main/jenkins-test-harness/*-rc*/' - } - script { - infra.maybePublishIncrementals() - } - } +properties([buildDiscarder(logRotator(numToKeepStr: '20'))]) +node('docker') { + timeout(time: 1, unit: 'HOURS') { + deleteDir() + checkout scm + def tmp = pwd tmp: true + // TODO or can do explicitly something like: docker run -v "$TMP"/m2repo:/var/maven/.m2/repository --rm -u $(id -u):$(id -g) -e MAVEN_CONFIG=/var/maven/.m2 -v "$PWD":/usr/src/mymaven -w /usr/src/mymaven maven:3.6.1-jdk-8 mvn -Duser.home=/var/maven … + docker.image('maven:3.6.1-jdk-8').inside { + withEnv(["TMP=$tmp"]) { + // TODO Azure mirror + sh 'mvn -B -Dmaven.repo.local="$TMP"/m2repo -ntp -e -Dset.changelist -Dexpression=changelist -Doutput="$TMP"/changelist -Dmaven.test.failure.ignore help:evaluate clean install' } } + junit '**/target/surefire-reports/TEST-*.xml' + def changelist = readFile("$tmp/changelist") + dir("$tmp/m2repo") { + archiveArtifacts "**/*$changelist/*$changelist*" + } } } +infra.maybePublishIncrementals() From f24f1b247584f0f652dad65e52b80b7f825d78c1 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Sun, 2 Jun 2019 16:01:52 -0700 Subject: [PATCH 06/59] Allow port reuse in RestartableJenkinsRule Testing the Swarm client requires having Jenkins run on the same port before and after restart. This change adds this functionality to RestartableJenkinsRule. The new functionality is opt-in to preserve existing behavior for tests which don't need this functionality. --- .../org/jvnet/hudson/test/JenkinsRule.java | 5 +- .../hudson/test/RestartableJenkinsRule.java | 45 ++++++++++++++- .../test/RestartableJenkinsRuleTest.java | 55 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 193eeca52..739c838b9 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -693,8 +693,11 @@ public Thread newThread(Runnable r) { // use a bigger buffer as Stapler traces can get pretty large on deeply nested URL config.setRequestHeaderSize(12 * 1024); connector.setHost("localhost"); - if (System.getProperty("port")!=null) + if (System.getProperty("port") != null) { connector.setPort(Integer.parseInt(System.getProperty("port"))); + } else if (localPort != 0) { + connector.setPort(localPort); + } server.addConnector(connector); server.start(); diff --git a/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java b/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java index 8346a02b8..6dc2edee4 100644 --- a/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java @@ -10,6 +10,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.ServerSocket; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -62,8 +64,38 @@ public class RestartableJenkinsRule implements MethodRule { */ public File home; + /** + * TCP/IP port that the server is listening on. + */ + private final int port; + private static final Logger LOGGER = Logger.getLogger(HudsonTestCase.class.getName()); + public static class Builder { + private int port; + + public Builder() { + this.port = 0; + } + + public Builder withReusedPort() { + this.port = getRandomPort(); + return this; + } + + public RestartableJenkinsRule build() { + return new RestartableJenkinsRule(this.port); + } + } + + public RestartableJenkinsRule() { + this.port = 0; + } + + private RestartableJenkinsRule(int port) { + this.port = port; + } + @Override public Statement apply(final Statement base, FrameworkMethod method, Object target) { this.description = Description.createTestDescription( @@ -279,7 +311,18 @@ private void run() throws Throwable { } protected JenkinsRule createJenkinsRule(Description description) { - return new JenkinsRule(); + JenkinsRule result = new JenkinsRule(); + if (port != 0) { + result.localPort = port; + } + return result; } + private static synchronized int getRandomPort() { + try (ServerSocket s = new ServerSocket(0)) { + return s.getLocalPort(); + } catch (IOException e) { + throw new UncheckedIOException("Unable to find free port", e); + } + } } diff --git a/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java b/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java new file mode 100644 index 000000000..2721b3c22 --- /dev/null +++ b/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java @@ -0,0 +1,55 @@ +package org.jvnet.hudson.test; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assume.assumeThat; + +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Rule; +import org.junit.Test; + +public class RestartableJenkinsRuleTest { + + @Rule public RestartableJenkinsRule noPortReuse = new RestartableJenkinsRule(); + + @Rule + public RestartableJenkinsRule portReuse = + new RestartableJenkinsRule.Builder().withReusedPort().build(); + + @Test + public void testNoPortReuse() throws Exception { + assumeThat( + "This test requires a custom port to not be set.", + System.getProperty("port"), + nullValue()); + + AtomicInteger port = new AtomicInteger(); + noPortReuse.then( + s -> { + port.set(noPortReuse.j.getURL().getPort()); + }); + noPortReuse.then( + s -> { + assertNotEquals(port.get(), noPortReuse.j.getURL().getPort()); + }); + } + + @Test + public void testPortReuse() throws Exception { + assumeThat( + "This test requires a custom port to not be set.", + System.getProperty("port"), + nullValue()); + + AtomicInteger port = new AtomicInteger(); + portReuse.then( + s -> { + port.set(portReuse.j.getURL().getPort()); + }); + portReuse.then( + s -> { + assertEquals(port.get(), portReuse.j.getURL().getPort()); + }); + } +} From a88c47e6e712867bdd522b1897e3c132bb3e4f9a Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 4 Jun 2019 09:56:16 +0200 Subject: [PATCH 07/59] Enable Release Drafter for Jenkins Test Harness --- .github/release-drafter.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 000000000..896cb9965 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,2 @@ +_extends: .github +tag-template: jenkins-test-harness-$NEXT_MINOR_VERSION From 2c1e10c0865f21a80745f53c51fe30fc079f22ef Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Mon, 3 Jun 2019 16:50:46 +0530 Subject: [PATCH 08/59] Introduce JMH benchmarks --- pom.xml | 22 ++- .../java/jenkins/jmh/BenchmarkFinder.java | 39 +++++ src/main/java/jenkins/jmh/JmhBenchmark.java | 24 +++ .../java/jenkins/jmh/JmhBenchmarkState.java | 165 ++++++++++++++++++ .../jmh/casc/CascJmhBenchmarkState.java | 44 +++++ .../org/jvnet/hudson/test/JenkinsRule.java | 43 ++++- 6 files changed, 330 insertions(+), 7 deletions(-) create mode 100644 src/main/java/jenkins/jmh/BenchmarkFinder.java create mode 100644 src/main/java/jenkins/jmh/JmhBenchmark.java create mode 100644 src/main/java/jenkins/jmh/JmhBenchmarkState.java create mode 100644 src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java diff --git a/pom.xml b/pom.xml index 0825d86a9..90e8634c2 100644 --- a/pom.xml +++ b/pom.xml @@ -167,8 +167,28 @@ THE SOFTWARE. 1.0.2 test + + org.openjdk.jmh + jmh-core + 1.21 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.21 + + + org.reflections + reflections + 0.9.11 + + + io.jenkins + configuration-as-code + 1.17 + true + - diff --git a/src/main/java/jenkins/jmh/BenchmarkFinder.java b/src/main/java/jenkins/jmh/BenchmarkFinder.java new file mode 100644 index 000000000..227580d73 --- /dev/null +++ b/src/main/java/jenkins/jmh/BenchmarkFinder.java @@ -0,0 +1,39 @@ +package jenkins.jmh; + +import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; +import org.reflections.Reflections; + +import java.util.Objects; +import java.util.Set; + +/** + * Find classes annotated with {@link JmhBenchmark} to run their benchmark methods. + */ +public final class BenchmarkFinder { + final private String[] packageName; + + /** + * Creates a {@link BenchmarkFinder} + * + * @param packageNames find benchmarks in these packages + */ + public BenchmarkFinder(String... packageNames) { + this.packageName = packageNames; + } + + /** + * Includes classes annotated with {@link JmhBenchmark} as candidates for JMH benchmarks. + * + * @param optionsBuilder the optionsBuilder used to build the benchmarks + */ + public void findBenchmarks(ChainedOptionsBuilder optionsBuilder) { + Reflections reflections = new Reflections((Object[]) packageName); + Set> benchmarkClasses = reflections.getTypesAnnotatedWith(JmhBenchmark.class); + benchmarkClasses.forEach(clazz -> { + JmhBenchmark annotation = clazz.getAnnotation(JmhBenchmark.class); + if (Objects.nonNull(annotation)) { + optionsBuilder.include(clazz.getName() + annotation.value()); + } + }); + } +} diff --git a/src/main/java/jenkins/jmh/JmhBenchmark.java b/src/main/java/jenkins/jmh/JmhBenchmark.java new file mode 100644 index 000000000..5581add32 --- /dev/null +++ b/src/main/java/jenkins/jmh/JmhBenchmark.java @@ -0,0 +1,24 @@ +package jenkins.jmh; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotate your benchmark classes with this annotation to allow them to be discovered by {@link BenchmarkFinder} + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface JmhBenchmark { + /** + * Methods which annotated by {@link org.openjdk.jmh.annotations.Benchmark} + * in classes annotated by {@link JmhBenchmark} are to be run as benchmarks if they + * match this regex pattern. + *

+ * Matches all functions by default, i.e. default pattern is {@code .*}. + * + * @return the regular expression used to match function names. + */ + String value() default ".*"; +} diff --git a/src/main/java/jenkins/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/jmh/JmhBenchmarkState.java new file mode 100644 index 000000000..69f58bb02 --- /dev/null +++ b/src/main/java/jenkins/jmh/JmhBenchmarkState.java @@ -0,0 +1,165 @@ +package jenkins.jmh; + +import hudson.WebAppMain; +import hudson.model.DownloadService; +import hudson.model.Hudson; +import hudson.model.JDK; +import hudson.model.RootAction; +import hudson.model.UpdateSite; +import hudson.security.ACL; +import hudson.util.PersistedList; +import io.vavr.Tuple2; +import jenkins.model.Jenkins; +import jenkins.model.JenkinsLocationConfiguration; +import org.eclipse.jetty.server.Server; +import org.jvnet.hudson.test.JavaNetReverseProxy; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TemporaryDirectoryAllocator; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; + +import javax.annotation.CheckForNull; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +@State(Scope.Benchmark) +public abstract class JmhBenchmarkState implements RootAction { + private static final Logger LOGGER = Logger.getLogger(JmhBenchmarkState.class.getName()); + private static final String contextPath = "/jenkins"; + + private final TemporaryDirectoryAllocator temporaryDirectoryAllocator = new TemporaryDirectoryAllocator(); + + private AtomicInteger localPort = new AtomicInteger(); + private Jenkins jenkins = null; + private Server server = null; + private URL jenkinsURL = null; + + // Run the setup for each individual fork of the JVM + @Setup(org.openjdk.jmh.annotations.Level.Trial) + public final void setupJenkins() throws Exception { + // Set the jenkins.install.InstallState TEST to emulate + // org.jvnet.hudson.test.JenkinsRule behaviour and avoid manual + // security setup as in a default installation. + System.setProperty("jenkins.install.state", "TEST"); + launchInstance(); + ACL.impersonate(ACL.SYSTEM); + setup(); + } + + // Run the tearDown for each individual fork of the JVM + @TearDown(org.openjdk.jmh.annotations.Level.Trial) + public final void terminateJenkins() { + try { + tearDown(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Exception occurred during tearDown of Jenkins instance", e); + } finally { + if (jenkins != null && server != null) { + try { + server.stop(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Exception occurred when shutting down server.", e); + } + + jenkins.cleanUp(); + jenkins = null; + server = null; + jenkinsURL = null; + } + + try { + temporaryDirectoryAllocator.dispose(); + } catch (InterruptedException | IOException e) { + LOGGER.log(Level.WARNING, "Unable to dispose temporary Jenkins directory" + + "that was started for benchmark", e); + } + } + } + + private void launchInstance() throws Exception { + Tuple2 results = JenkinsRule._createWebServer(contextPath, localPort::set, + this::getJenkinsURL, getClass().getClassLoader()); + server = results._1; + + ServletContext webServer = results._2; + + File jenkinsHome = temporaryDirectoryAllocator.allocate(); + jenkins = new Hudson(jenkinsHome, webServer); + jenkins.setNoUsageStatistics(true); + + webServer.setAttribute("app", jenkins); + webServer.setAttribute("version", "?"); + + // configure Jelly views + WebAppMain.installExpressionFactory(new ServletContextEvent(webServer)); + jenkins.getJDKs().add(new JDK("default", System.getProperty("java.home"))); + + PersistedList sites = jenkins.getUpdateCenter().getSites(); + sites.clear(); + sites.add(new UpdateSite("default", "http://localhost:" + + JavaNetReverseProxy.getInstance().localPort + "/update-center.json")); + + DownloadService.neverUpdate = true; + UpdateSite.neverUpdate = true; + + jenkins.getActions().add(this); + + Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(jenkinsURL.toString()); + } + + private URL getJenkinsURL() { + try { + return new URL("http://localhost:" + localPort.get() + contextPath + "/"); + } catch (Exception e) { + return null; + } + } + + public Jenkins getJenkins() { + return jenkins; + } + + /** + * Override to setup resources required for the benchmark. + *

+ * Runs before the benchmarks are run. At this state, the Jenkins + * is ready to be worked upon. + */ + public void setup() throws Exception { + } + + /** + * Override to perform cleanup of resource initialized during setup. + *

+ * Run before the Jenkins instance is terminated. + */ + public void tearDown() { + } + + @CheckForNull + @Override + public String getIconFileName() { + return null; + } + + @CheckForNull + @Override + public String getDisplayName() { + return null; + } + + @CheckForNull + @Override + public String getUrlName() { + return "self"; + } +} diff --git a/src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java b/src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java new file mode 100644 index 000000000..500263fc6 --- /dev/null +++ b/src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java @@ -0,0 +1,44 @@ +package jenkins.jmh.casc; + +import io.jenkins.plugins.casc.ConfigurationAsCode; +import io.jenkins.plugins.casc.ConfiguratorException; +import jenkins.jmh.JmhBenchmarkState; + +import javax.annotation.Nonnull; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Use Configuration as Code to setup the Jenkins instance for JMH benchmark. + */ +@SuppressWarnings("unused") +public abstract class CascJmhBenchmarkState extends JmhBenchmarkState { + private static final Logger LOGGER = Logger.getLogger(CascJmhBenchmarkState.class.getName()); + + /** + * Location of the YAML file to be used for configuration-as-code + * + * @return String containing the location of YAML file in the classpath + */ + @Nonnull + protected abstract String getResourcePath(); + + /** + * Setups the Jenkins instance using configuration as code + * available through the {@link CascJmhBenchmarkState#getResourcePath()}. + * + * @throws ConfiguratorException when unable to configure + */ + @Override + public void setup() throws Exception { + String config = Objects.requireNonNull(getClass().getClassLoader().getResource(getResourcePath())).toExternalForm(); + try { + ConfigurationAsCode.get().configure(config); + } catch (ConfiguratorException e) { + LOGGER.log(Level.SEVERE, "Unable to configure using configuration as code. Aborting."); + terminateJenkins(); + throw e; // causes JMH to abort benchmark + } + } +} diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 193eeca52..4b62e2827 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -159,6 +159,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.jar.Manifest; import java.util.logging.Filter; import java.util.logging.Level; @@ -169,6 +171,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; +import io.vavr.Tuple2; import jenkins.model.Jenkins; import jenkins.model.JenkinsAdaptor; import jenkins.model.JenkinsLocationConfiguration; @@ -671,7 +674,30 @@ public File getWebAppRoot() throws Exception { * that we need for testing. */ protected ServletContext createWebServer() throws Exception { - server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(),new ThreadFactory() { + Tuple2 results = _createWebServer(contextPath, (x) -> localPort = x, () -> { + try { + return getURL(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Unable to get Url", e); + return null; + } + }, getClass().getClassLoader()); + server = results._1; + return results._2; + } + + /** + * Creates a web server on which Jenkins can run + * @param contextPath the context path at which to put Jenkins + * @param portSetter the port on which the server runs will be set using this function + * @param urlGetter returns the URL after the port has been set using portSetter + * @param classLoader the class loader for the {@link WebAppContext} + * @return tuple consisting of the {@link Server} and the {@link ServletContext} + */ + public static Tuple2 _createWebServer(String contextPath, Consumer portSetter, + Supplier urlGetter, ClassLoader classLoader) + throws Exception { + Server server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("Jetty Thread Pool"); @@ -680,12 +706,12 @@ public Thread newThread(Runnable r) { }))); WebAppContext context = new WebAppContext(WarExploder.getExplodedDir().getPath(), contextPath); - context.setClassLoader(getClass().getClassLoader()); + context.setClassLoader(classLoader); context.setConfigurations(new Configuration[]{new WebXmlConfiguration()}); context.addBean(new NoListenerConfiguration(context)); server.setHandler(context); context.setMimeTypes(MIME_TYPES); - context.getSecurityHandler().setLoginService(configureUserRealm()); + context.getSecurityHandler().setLoginService(_configureUserRealm()); context.setResourceBase(WarExploder.getExplodedDir().getPath()); ServerConnector connector = new ServerConnector(server, 1, 1); @@ -699,16 +725,21 @@ public Thread newThread(Runnable r) { server.addConnector(connector); server.start(); - localPort = connector.getLocalPort(); - LOGGER.log(Level.INFO, "Running on {0}", getURL()); + portSetter.accept(connector.getLocalPort()); + LOGGER.log(Level.INFO, "Running on {0}", urlGetter.get()); - return context.getServletContext(); + ServletContext servletContext = context.getServletContext(); + return new Tuple2<>(server, servletContext); } /** * Configures a security realm for a test. */ protected LoginService configureUserRealm() { + return _configureUserRealm(); + } + + public static LoginService _configureUserRealm() { HashLoginService realm = new HashLoginService(); realm.setName("default"); // this is the magic realm name to make it effective on everywhere UserStore userStore = new UserStore(); From a39da724dcd4a867c1bd7063696987d206562a1c Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Mon, 3 Jun 2019 17:48:33 +0530 Subject: [PATCH 09/59] Add sample benchmarks as test cases * Bump up the Jenkins version up to 2.60.3 for Configuration as code support * Add sample YAMl configuration using Role Strategy plugin * Fix getUrl in JmhBenchmarkState.java --- .gitignore | 3 + pom.xml | 10 ++- .../java/jenkins/jmh/JmhBenchmarkState.java | 4 +- src/test/java/jenkins/jmh/BenchmarkTest.java | 27 ++++++++ .../jmh/benchmarks/CascStateBenchmarks.java | 24 +++++++ .../jmh/benchmarks/JmhStateBenchmark.java | 18 +++++ src/test/resources/sample-config.yaml | 67 +++++++++++++++++++ 7 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 src/test/java/jenkins/jmh/BenchmarkTest.java create mode 100644 src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java create mode 100644 src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java create mode 100644 src/test/resources/sample-config.yaml diff --git a/.gitignore b/.gitignore index 10bed9819..1f9d279da 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ out .classpath .project build + +# reports produced from benchmarks +jmh-benchmark-report.json diff --git a/pom.xml b/pom.xml index 90e8634c2..b27ddd127 100644 --- a/pom.xml +++ b/pom.xml @@ -85,8 +85,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-war - - 1.651.2 + 2.60.3 executable-war @@ -188,6 +187,13 @@ THE SOFTWARE. 1.17 true + + + org.jenkins-ci.plugins + role-strategy + 2.11 + test + diff --git a/src/main/java/jenkins/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/jmh/JmhBenchmarkState.java index 69f58bb02..2920b6c4e 100644 --- a/src/main/java/jenkins/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/jmh/JmhBenchmarkState.java @@ -41,7 +41,6 @@ public abstract class JmhBenchmarkState implements RootAction { private AtomicInteger localPort = new AtomicInteger(); private Jenkins jenkins = null; private Server server = null; - private URL jenkinsURL = null; // Run the setup for each individual fork of the JVM @Setup(org.openjdk.jmh.annotations.Level.Trial) @@ -73,7 +72,6 @@ public final void terminateJenkins() { jenkins.cleanUp(); jenkins = null; server = null; - jenkinsURL = null; } try { @@ -113,7 +111,7 @@ private void launchInstance() throws Exception { jenkins.getActions().add(this); - Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(jenkinsURL.toString()); + Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(Objects.requireNonNull(getJenkinsURL()).toString()); } private URL getJenkinsURL() { diff --git a/src/test/java/jenkins/jmh/BenchmarkTest.java b/src/test/java/jenkins/jmh/BenchmarkTest.java new file mode 100644 index 000000000..a2dca9ed1 --- /dev/null +++ b/src/test/java/jenkins/jmh/BenchmarkTest.java @@ -0,0 +1,27 @@ +package jenkins.jmh; + +import org.junit.Test; +import org.openjdk.jmh.results.format.ResultFormatType; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.concurrent.TimeUnit; + +public class BenchmarkTest { + @Test + public void testJmhBenchmarks() throws Exception { + ChainedOptionsBuilder optionsBuilder = + new OptionsBuilder() + .forks(1) + .warmupForks(1) + .warmupBatchSize(1) + .shouldFailOnError(true) + .result("jmh-benchmark-report.json") + .timeUnit(TimeUnit.MICROSECONDS) + .resultFormat(ResultFormatType.JSON); + BenchmarkFinder finder = new BenchmarkFinder(this.getClass().getPackage().getName()); + finder.findBenchmarks(optionsBuilder); + new Runner(optionsBuilder.build()).run(); + } +} diff --git a/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java b/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java new file mode 100644 index 000000000..44993a93c --- /dev/null +++ b/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java @@ -0,0 +1,24 @@ +package jenkins.jmh.benchmarks; + +import jenkins.jmh.JmhBenchmark; +import jenkins.jmh.casc.CascJmhBenchmarkState; +import org.openjdk.jmh.annotations.Benchmark; + +import javax.annotation.Nonnull; +import java.util.Objects; + +@JmhBenchmark +public class CascStateBenchmarks { + public static class MyState extends CascJmhBenchmarkState { + @Nonnull + @Override + protected String getResourcePath() { + return "sample-config.yaml"; + } + } + + @Benchmark + public void benchmark(MyState state) { + Objects.requireNonNull(state.getJenkins()); + } +} diff --git a/src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java b/src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java new file mode 100644 index 000000000..99d644da0 --- /dev/null +++ b/src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java @@ -0,0 +1,18 @@ +package jenkins.jmh.benchmarks; + +import jenkins.jmh.JmhBenchmark; +import jenkins.jmh.JmhBenchmarkState; +import org.openjdk.jmh.annotations.Benchmark; + +import java.util.Objects; + +@JmhBenchmark +public class JmhStateBenchmark { + public static class MyState extends JmhBenchmarkState { + } + + @Benchmark + public void benchmark(MyState state) { + Objects.requireNonNull(state.getJenkins()); + } +} diff --git a/src/test/resources/sample-config.yaml b/src/test/resources/sample-config.yaml new file mode 100644 index 000000000..c12b53582 --- /dev/null +++ b/src/test/resources/sample-config.yaml @@ -0,0 +1,67 @@ +jenkins: + authorizationStrategy: + roleBased: + roles: + global: + - name: "admin" + description: "Jenkins administrators" + permissions: + - "Overall/Administer" + assignments: + - "admin" + - name: "readonly" + description: "Read-only users" + permissions: + - "Overall/Read" + - "Job/Read" + assignments: + - "authenticated" + items: + - name: "FolderA" + description: "Jobs in Folder A, but not the folder itself" + pattern: "A/.*" + permissions: + - "Job/Configure" + - "Job/Build" + - "Job/Delete" + assignments: + - "user1" + - "user2" + - name: "FolderB" + description: "Jobs in Folder B, but not the folder itself" + pattern: "B.*" + permissions: + - "Job/Configure" + - "Job/Build" + assignments: + - "user2" + agents: + - name: "Agent1" + description: "Agent 1" + pattern: "agent1" + permissions: + - "Agent/Build" + assignments: + - "user1" + + # System for test + securityRealm: + local: + allowsSignup: false + users: + - id: "admin" + password: "1234" + - id: "user1" + password: "" + + nodes: + - dumb: + mode: NORMAL + name: "agent1" + remoteFS: "/home/user1" + launcher: jnlp + - dumb: + mode: NORMAL + name: "agent2" + remoteFS: "/home/user1" + launcher: jnlp From 0590524dd1b5899931a8f9b8ad58c6fbd3b50dad Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Tue, 4 Jun 2019 09:54:18 +0530 Subject: [PATCH 10/59] Share more code from JenkinsRule * Use ImmutablePair instead of Tuple2 * Use MutableInt instead of AtomicInteger * Remove Role strategy and use Matrix auth for sample case * Update Jenkins Core to 2.138.3 for CASC support for Matrix Auth --- pom.xml | 13 +-- .../java/jenkins/jmh/JmhBenchmarkState.java | 56 +++---------- .../org/jvnet/hudson/test/JenkinsRule.java | 83 ++++++++++--------- src/test/resources/sample-config.yaml | 69 +-------------- 4 files changed, 62 insertions(+), 159 deletions(-) diff --git a/pom.xml b/pom.xml index b27ddd127..adf1e0423 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-war - 2.60.3 + 2.138.3 executable-war @@ -163,7 +163,7 @@ THE SOFTWARE. org.jenkins-ci.plugins matrix-auth - 1.0.2 + 2.4.2 test @@ -184,16 +184,9 @@ THE SOFTWARE. io.jenkins configuration-as-code - 1.17 + 1.19 true - - - org.jenkins-ci.plugins - role-strategy - 2.11 - test - diff --git a/src/main/java/jenkins/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/jmh/JmhBenchmarkState.java index 2920b6c4e..04f7b1586 100644 --- a/src/main/java/jenkins/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/jmh/JmhBenchmarkState.java @@ -1,18 +1,13 @@ package jenkins.jmh; -import hudson.WebAppMain; -import hudson.model.DownloadService; import hudson.model.Hudson; -import hudson.model.JDK; import hudson.model.RootAction; -import hudson.model.UpdateSite; import hudson.security.ACL; -import hudson.util.PersistedList; -import io.vavr.Tuple2; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.eclipse.jetty.server.Server; -import org.jvnet.hudson.test.JavaNetReverseProxy; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TemporaryDirectoryAllocator; import org.openjdk.jmh.annotations.Scope; @@ -22,12 +17,9 @@ import javax.annotation.CheckForNull; import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,8 +29,8 @@ public abstract class JmhBenchmarkState implements RootAction { private static final String contextPath = "/jenkins"; private final TemporaryDirectoryAllocator temporaryDirectoryAllocator = new TemporaryDirectoryAllocator(); + private final MutableInt localPort = new MutableInt(); - private AtomicInteger localPort = new AtomicInteger(); private Jenkins jenkins = null; private Server server = null; @@ -62,18 +54,7 @@ public final void terminateJenkins() { } catch (Exception e) { LOGGER.log(Level.SEVERE, "Exception occurred during tearDown of Jenkins instance", e); } finally { - if (jenkins != null && server != null) { - try { - server.stop(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Exception occurred when shutting down server.", e); - } - - jenkins.cleanUp(); - jenkins = null; - server = null; - } - + JenkinsRule._stopJenkins(server, null, jenkins); try { temporaryDirectoryAllocator.dispose(); } catch (InterruptedException | IOException e) { @@ -84,31 +65,14 @@ public final void terminateJenkins() { } private void launchInstance() throws Exception { - Tuple2 results = JenkinsRule._createWebServer(contextPath, localPort::set, + ImmutablePair results = JenkinsRule._createWebServer(contextPath, localPort::setValue, this::getJenkinsURL, getClass().getClassLoader()); - server = results._1; - - ServletContext webServer = results._2; - - File jenkinsHome = temporaryDirectoryAllocator.allocate(); - jenkins = new Hudson(jenkinsHome, webServer); - jenkins.setNoUsageStatistics(true); - - webServer.setAttribute("app", jenkins); - webServer.setAttribute("version", "?"); - - // configure Jelly views - WebAppMain.installExpressionFactory(new ServletContextEvent(webServer)); - jenkins.getJDKs().add(new JDK("default", System.getProperty("java.home"))); - - PersistedList sites = jenkins.getUpdateCenter().getSites(); - sites.clear(); - sites.add(new UpdateSite("default", "http://localhost:" + - JavaNetReverseProxy.getInstance().localPort + "/update-center.json")); - DownloadService.neverUpdate = true; - UpdateSite.neverUpdate = true; + server = results.left; + ServletContext webServer = results.right; + jenkins = new Hudson(temporaryDirectoryAllocator.allocate(), webServer); + JenkinsRule._configureJenkinsForTest(jenkins); jenkins.getActions().add(this); Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(Objects.requireNonNull(getJenkinsURL()).toString()); @@ -116,7 +80,7 @@ private void launchInstance() throws Exception { private URL getJenkinsURL() { try { - return new URL("http://localhost:" + localPort.get() + contextPath + "/"); + return new URL("http://localhost:" + localPort.getValue() + contextPath + "/"); } catch (Exception e) { return null; } diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 4b62e2827..8c5ed0485 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -171,7 +171,6 @@ import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; -import io.vavr.Tuple2; import jenkins.model.Jenkins; import jenkins.model.JenkinsAdaptor; import jenkins.model.JenkinsLocationConfiguration; @@ -188,6 +187,7 @@ import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.security.LoginService; @@ -413,18 +413,9 @@ public void before() throws Throwable { f.set(null,null); throw e; } - jenkins.setNoUsageStatistics(true); // collecting usage stats from tests are pointless. - jenkins.setCrumbIssuer(new TestCrumbIssuer()); - - jenkins.servletContext.setAttribute("app",jenkins); - jenkins.servletContext.setAttribute("version","?"); - WebAppMain.installExpressionFactory(new ServletContextEvent(jenkins.servletContext)); - - // set a default JDK to be the one that the harness is using. - jenkins.getJDKs().add(new JDK("default",System.getProperty("java.home"))); - - configureUpdateCenter(); + jenkins.setCrumbIssuer(new TestCrumbIssuer()); // TODO: Move to _configureJenkinsForTest after JENKINS-55240 + _configureJenkinsForTest(jenkins); // expose the test instance as a part of URL tree. // this allows tests to use a part of the URL space for itself. @@ -437,7 +428,15 @@ public void before() throws Throwable { * Configures the update center setting for the test. * By default, we load updates from local proxy to avoid network traffic as much as possible. */ - protected void configureUpdateCenter() throws Exception { + public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { + jenkins.setNoUsageStatistics(true); // collecting usage stats from tests is pointless. + jenkins.servletContext.setAttribute("app", jenkins); + jenkins.servletContext.setAttribute("version", "?"); + WebAppMain.installExpressionFactory(new ServletContextEvent(jenkins.servletContext)); + + // set a default JDK to be the one that the harness is using. + jenkins.getJDKs().add(new JDK("default", System.getProperty("java.home"))); + final String updateCenterUrl; jettyLevel(Level.WARNING); try { @@ -486,25 +485,7 @@ public void after() throws Exception { clients.clear(); } finally { - jettyLevel(Level.WARNING); - try { - server.stop(); - } catch (Exception e) { - // ignore - } finally { - jettyLevel(Level.INFO); - } - for (LenientRunnable r : tearDowns) - try { - r.run(); - } catch (Exception e) { - // ignore - } - - if (jenkins!=null) - jenkins.cleanUp(); - ExtensionList.clearLegacyInstances(); - DescriptorExtensionList.clearLegacyInstances(); + _stopJenkins(server, tearDowns, jenkins); try { env.dispose(); @@ -527,6 +508,32 @@ public void after() throws Exception { } } + public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { + jettyLevel(Level.WARNING); + try { + server.stop(); + } catch (Exception e) { + // ignore + } finally { + jettyLevel(Level.INFO); + } + + if (tearDowns != null) { + for (LenientRunnable r : tearDowns) { + try { + r.run(); + } catch (Exception e) { + // ignore + } + } + } + + if (jenkins != null) + jenkins.cleanUp(); + ExtensionList.clearLegacyInstances(); + DescriptorExtensionList.clearLegacyInstances(); + } + private static void jettyLevel(Level level) { Logger.getLogger("org.eclipse.jetty").setLevel(level); } @@ -674,7 +681,7 @@ public File getWebAppRoot() throws Exception { * that we need for testing. */ protected ServletContext createWebServer() throws Exception { - Tuple2 results = _createWebServer(contextPath, (x) -> localPort = x, () -> { + ImmutablePair results = _createWebServer(contextPath, (x) -> localPort = x, () -> { try { return getURL(); } catch (IOException e) { @@ -682,8 +689,8 @@ protected ServletContext createWebServer() throws Exception { return null; } }, getClass().getClassLoader()); - server = results._1; - return results._2; + server = results.left; + return results.right; } /** @@ -694,8 +701,8 @@ protected ServletContext createWebServer() throws Exception { * @param classLoader the class loader for the {@link WebAppContext} * @return tuple consisting of the {@link Server} and the {@link ServletContext} */ - public static Tuple2 _createWebServer(String contextPath, Consumer portSetter, - Supplier urlGetter, ClassLoader classLoader) + public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, + Supplier urlGetter, ClassLoader classLoader) throws Exception { Server server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { public Thread newThread(Runnable r) { @@ -729,7 +736,7 @@ public Thread newThread(Runnable r) { LOGGER.log(Level.INFO, "Running on {0}", urlGetter.get()); ServletContext servletContext = context.getServletContext(); - return new Tuple2<>(server, servletContext); + return new ImmutablePair<>(server, servletContext); } /** diff --git a/src/test/resources/sample-config.yaml b/src/test/resources/sample-config.yaml index c12b53582..4a9784ffe 100644 --- a/src/test/resources/sample-config.yaml +++ b/src/test/resources/sample-config.yaml @@ -1,67 +1,6 @@ jenkins: authorizationStrategy: - roleBased: - roles: - global: - - name: "admin" - description: "Jenkins administrators" - permissions: - - "Overall/Administer" - assignments: - - "admin" - - name: "readonly" - description: "Read-only users" - permissions: - - "Overall/Read" - - "Job/Read" - assignments: - - "authenticated" - items: - - name: "FolderA" - description: "Jobs in Folder A, but not the folder itself" - pattern: "A/.*" - permissions: - - "Job/Configure" - - "Job/Build" - - "Job/Delete" - assignments: - - "user1" - - "user2" - - name: "FolderB" - description: "Jobs in Folder B, but not the folder itself" - pattern: "B.*" - permissions: - - "Job/Configure" - - "Job/Build" - assignments: - - "user2" - agents: - - name: "Agent1" - description: "Agent 1" - pattern: "agent1" - permissions: - - "Agent/Build" - assignments: - - "user1" - - # System for test - securityRealm: - local: - allowsSignup: false - users: - - id: "admin" - password: "1234" - - id: "user1" - password: "" - - nodes: - - dumb: - mode: NORMAL - name: "agent1" - remoteFS: "/home/user1" - launcher: jnlp - - dumb: - mode: NORMAL - name: "agent2" - remoteFS: "/home/user1" - launcher: jnlp + globalMatrix: + permissions: + - "Overall/Read:anonymous" + - "Overall/Administer:authenticated" From b25965cbc7cf687eab3d9bfbbdfb0118214e7f05 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Tue, 4 Jun 2019 11:39:24 +0530 Subject: [PATCH 11/59] Revert back to Jenkins 2.60.3 * Remove benchmarks using Matrix Auth * Benchmark just checks if the system message and number of executors is set correctly by CASC or not. --- pom.xml | 4 ++-- .../java/jenkins/jmh/benchmarks/CascStateBenchmarks.java | 7 +++++-- src/test/resources/sample-config.yaml | 7 ++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index adf1e0423..5cde548f9 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-war - 2.138.3 + 2.60.3 executable-war @@ -163,7 +163,7 @@ THE SOFTWARE. org.jenkins-ci.plugins matrix-auth - 2.4.2 + 1.0.2 test diff --git a/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java b/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java index 44993a93c..1e567018b 100644 --- a/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java +++ b/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java @@ -5,7 +5,8 @@ import org.openjdk.jmh.annotations.Benchmark; import javax.annotation.Nonnull; -import java.util.Objects; + +import static org.junit.Assert.assertEquals; @JmhBenchmark public class CascStateBenchmarks { @@ -19,6 +20,8 @@ protected String getResourcePath() { @Benchmark public void benchmark(MyState state) { - Objects.requireNonNull(state.getJenkins()); + assertEquals(state.getJenkins().getSystemMessage(), + "Benchmark started with Configuration as Code"); + assertEquals(state.getJenkins().getNumExecutors(), 22); } } diff --git a/src/test/resources/sample-config.yaml b/src/test/resources/sample-config.yaml index 4a9784ffe..e9878fdbe 100644 --- a/src/test/resources/sample-config.yaml +++ b/src/test/resources/sample-config.yaml @@ -1,6 +1,3 @@ jenkins: - authorizationStrategy: - globalMatrix: - permissions: - - "Overall/Read:anonymous" - - "Overall/Administer:authenticated" + systemMessage: "Benchmark started with Configuration as Code" + numExecutors: 22 From c1a3f0731f7930b5c9f4c28fb3874384910d9e3f Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Tue, 4 Jun 2019 15:45:38 +0530 Subject: [PATCH 12/59] Update JavaDocs and refactor into new packages Now create jmh reports at target/jmh-reports --- .gitignore | 3 -- .../{ => benchmark}/jmh/BenchmarkFinder.java | 3 +- .../{ => benchmark}/jmh/JmhBenchmark.java | 3 +- .../jmh/JmhBenchmarkState.java | 46 ++++++++++++++++--- .../jmh/casc/CascJmhBenchmarkState.java | 8 +++- .../org/jvnet/hudson/test/JenkinsRule.java | 14 ++++-- .../{ => benchmark}/jmh/BenchmarkTest.java | 20 ++++++-- .../jmh/samples/CascStateBenchmark.java} | 11 +++-- .../jmh/samples}/JmhStateBenchmark.java | 9 ++-- 9 files changed, 91 insertions(+), 26 deletions(-) rename src/main/java/jenkins/{ => benchmark}/jmh/BenchmarkFinder.java (96%) rename src/main/java/jenkins/{ => benchmark}/jmh/JmhBenchmark.java (94%) rename src/main/java/jenkins/{ => benchmark}/jmh/JmhBenchmarkState.java (72%) rename src/main/java/jenkins/{ => benchmark}/jmh/casc/CascJmhBenchmarkState.java (87%) rename src/test/java/jenkins/{ => benchmark}/jmh/BenchmarkTest.java (57%) rename src/test/java/jenkins/{jmh/benchmarks/CascStateBenchmarks.java => benchmark/jmh/samples/CascStateBenchmark.java} (69%) rename src/test/java/jenkins/{jmh/benchmarks => benchmark/jmh/samples}/JmhStateBenchmark.java (58%) diff --git a/.gitignore b/.gitignore index 1f9d279da..10bed9819 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,3 @@ out .classpath .project build - -# reports produced from benchmarks -jmh-benchmark-report.json diff --git a/src/main/java/jenkins/jmh/BenchmarkFinder.java b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java similarity index 96% rename from src/main/java/jenkins/jmh/BenchmarkFinder.java rename to src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java index 227580d73..2bebebdf8 100644 --- a/src/main/java/jenkins/jmh/BenchmarkFinder.java +++ b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java @@ -1,4 +1,4 @@ -package jenkins.jmh; +package jenkins.benchmark.jmh; import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; import org.reflections.Reflections; @@ -8,6 +8,7 @@ /** * Find classes annotated with {@link JmhBenchmark} to run their benchmark methods. + * @since TODO */ public final class BenchmarkFinder { final private String[] packageName; diff --git a/src/main/java/jenkins/jmh/JmhBenchmark.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java similarity index 94% rename from src/main/java/jenkins/jmh/JmhBenchmark.java rename to src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java index 5581add32..1da307ec2 100644 --- a/src/main/java/jenkins/jmh/JmhBenchmark.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java @@ -1,4 +1,4 @@ -package jenkins.jmh; +package jenkins.benchmark.jmh; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,6 +7,7 @@ /** * Annotate your benchmark classes with this annotation to allow them to be discovered by {@link BenchmarkFinder} + * @since TODO */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/jenkins/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java similarity index 72% rename from src/main/java/jenkins/jmh/JmhBenchmarkState.java rename to src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index 04f7b1586..dc6a90aab 100644 --- a/src/main/java/jenkins/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -1,8 +1,9 @@ -package jenkins.jmh; +package jenkins.benchmark.jmh; import hudson.model.Hudson; import hudson.model.RootAction; import hudson.security.ACL; +import jenkins.benchmark.jmh.casc.CascJmhBenchmarkState; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import org.apache.commons.lang3.mutable.MutableInt; @@ -23,6 +24,20 @@ import java.util.logging.Level; import java.util.logging.Logger; +/** + * Standard benchmark {@link State} for JMH when a Jenkins instance is required. + *

+ * To use a Jenkins instance in your benchmark, your class containing benchmarks should have a public static inner + * class that extends this class and should be annotated with {@link JmhBenchmark} to allow it to be automatically + * discovered by {@link BenchmarkFinder}. To configure the instance, use {@link #setup()} or use + * {@link CascJmhBenchmarkState}. + * + * @see #setup() + * @see #tearDown() + * @see BenchmarkFinder + * @see CascJmhBenchmarkState + * @since TODO + */ @State(Scope.Benchmark) public abstract class JmhBenchmarkState implements RootAction { private static final Logger LOGGER = Logger.getLogger(JmhBenchmarkState.class.getName()); @@ -34,7 +49,13 @@ public abstract class JmhBenchmarkState implements RootAction { private Jenkins jenkins = null; private Server server = null; - // Run the setup for each individual fork of the JVM + /** + * Sets up the temporary Jenkins instance for benchmarks. + *

+ * One Jenkins instance is created for each fork of the benchmark. + * + * @throws Exception if unable to start the instance. + */ @Setup(org.openjdk.jmh.annotations.Level.Trial) public final void setupJenkins() throws Exception { // Set the jenkins.install.InstallState TEST to emulate @@ -46,7 +67,10 @@ public final void setupJenkins() throws Exception { setup(); } - // Run the tearDown for each individual fork of the JVM + /** + * Terminates the jenkins instance after the benchmark has completed its execution. + * Run once for each Jenkins that was started. + */ @TearDown(org.openjdk.jmh.annotations.Level.Trial) public final void terminateJenkins() { try { @@ -86,6 +110,13 @@ private URL getJenkinsURL() { } } + /** + * Get reference to the {@link Jenkins} started for the benchmark. + *

+ * The instance can also be obtained using {@link Jenkins#getInstanceOrNull()} + * + * @return the Jenkins instance started for the benchmark. + */ public Jenkins getJenkins() { return jenkins; } @@ -93,18 +124,21 @@ public Jenkins getJenkins() { /** * Override to setup resources required for the benchmark. *

- * Runs before the benchmarks are run. At this state, the Jenkins - * is ready to be worked upon. + * Runs before the benchmarks are run. At this state, the Jenkins instance + * is ready to be worked upon and is available using {@link #getJenkins()}. + * Does nothing by default. */ public void setup() throws Exception { + // noop } /** * Override to perform cleanup of resource initialized during setup. *

- * Run before the Jenkins instance is terminated. + * Run before the Jenkins instance is terminated. Does nothing by default. */ public void tearDown() { + // noop } @CheckForNull diff --git a/src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java similarity index 87% rename from src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java rename to src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java index 500263fc6..53565d593 100644 --- a/src/main/java/jenkins/jmh/casc/CascJmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java @@ -1,8 +1,8 @@ -package jenkins.jmh.casc; +package jenkins.benchmark.jmh.casc; import io.jenkins.plugins.casc.ConfigurationAsCode; import io.jenkins.plugins.casc.ConfiguratorException; -import jenkins.jmh.JmhBenchmarkState; +import jenkins.benchmark.jmh.JmhBenchmarkState; import javax.annotation.Nonnull; import java.util.Objects; @@ -11,6 +11,10 @@ /** * Use Configuration as Code to setup the Jenkins instance for JMH benchmark. + *

+ * Override the {@code getResourcePath} method configure the path to the YAML configuration. + * + * @see JmhBenchmarkState */ @SuppressWarnings("unused") public abstract class CascJmhBenchmarkState extends JmhBenchmarkState { diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 8c5ed0485..968d39910 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -508,6 +508,13 @@ public void after() throws Exception { } } + /** + * Internal method to stop Jenkins instance. + * + * @param server server on which Jenkins is running. + * @param tearDowns tear down methods for tests + * @param jenkins the jenkins instance + */ public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { jettyLevel(Level.WARNING); try { @@ -695,11 +702,12 @@ protected ServletContext createWebServer() throws Exception { /** * Creates a web server on which Jenkins can run + * * @param contextPath the context path at which to put Jenkins - * @param portSetter the port on which the server runs will be set using this function - * @param urlGetter returns the URL after the port has been set using portSetter + * @param portSetter the port on which the server runs will be set using this function + * @param urlGetter returns the URL after the port has been set using portSetter * @param classLoader the class loader for the {@link WebAppContext} - * @return tuple consisting of the {@link Server} and the {@link ServletContext} + * @return ImmutablePair consisting of the {@link Server} and the {@link ServletContext} */ public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, Supplier urlGetter, ClassLoader classLoader) diff --git a/src/test/java/jenkins/jmh/BenchmarkTest.java b/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java similarity index 57% rename from src/test/java/jenkins/jmh/BenchmarkTest.java rename to src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java index a2dca9ed1..532a4efb3 100644 --- a/src/test/java/jenkins/jmh/BenchmarkTest.java +++ b/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java @@ -1,4 +1,4 @@ -package jenkins.jmh; +package jenkins.benchmark.jmh; import org.junit.Test; import org.openjdk.jmh.results.format.ResultFormatType; @@ -6,18 +6,32 @@ import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; import org.openjdk.jmh.runner.options.OptionsBuilder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.TimeUnit; +/** + * Runs sample benchmarks from JUnit tests. + */ public class BenchmarkTest { @Test public void testJmhBenchmarks() throws Exception { + // create directory for JMH reports + Path path = Paths.get("target/jmh-reports/"); + Files.createDirectories(path); + + // number of iterations is kept to a minimum just to verify that the benchmarks work without spending extra + // time during builds. ChainedOptionsBuilder optionsBuilder = new OptionsBuilder() .forks(1) - .warmupForks(1) + .warmupIterations(1) .warmupBatchSize(1) + .measurementIterations(1) + .measurementBatchSize(1) .shouldFailOnError(true) - .result("jmh-benchmark-report.json") + .result("target/jmh-reports/jmh-benchmark-report.json") .timeUnit(TimeUnit.MICROSECONDS) .resultFormat(ResultFormatType.JSON); BenchmarkFinder finder = new BenchmarkFinder(this.getClass().getPackage().getName()); diff --git a/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java b/src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java similarity index 69% rename from src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java rename to src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java index 1e567018b..af89cd6e2 100644 --- a/src/test/java/jenkins/jmh/benchmarks/CascStateBenchmarks.java +++ b/src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java @@ -1,15 +1,18 @@ -package jenkins.jmh.benchmarks; +package jenkins.benchmark.jmh.samples; -import jenkins.jmh.JmhBenchmark; -import jenkins.jmh.casc.CascJmhBenchmarkState; +import jenkins.benchmark.jmh.casc.CascJmhBenchmarkState; +import jenkins.benchmark.jmh.JmhBenchmark; import org.openjdk.jmh.annotations.Benchmark; import javax.annotation.Nonnull; import static org.junit.Assert.assertEquals; +/** + * Sample benchmark configuring Jenkins instance using Configuration as Code + */ @JmhBenchmark -public class CascStateBenchmarks { +public class CascStateBenchmark { public static class MyState extends CascJmhBenchmarkState { @Nonnull @Override diff --git a/src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java b/src/test/java/jenkins/benchmark/jmh/samples/JmhStateBenchmark.java similarity index 58% rename from src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java rename to src/test/java/jenkins/benchmark/jmh/samples/JmhStateBenchmark.java index 99d644da0..6ec00da35 100644 --- a/src/test/java/jenkins/jmh/benchmarks/JmhStateBenchmark.java +++ b/src/test/java/jenkins/benchmark/jmh/samples/JmhStateBenchmark.java @@ -1,11 +1,14 @@ -package jenkins.jmh.benchmarks; +package jenkins.benchmark.jmh.samples; -import jenkins.jmh.JmhBenchmark; -import jenkins.jmh.JmhBenchmarkState; +import jenkins.benchmark.jmh.JmhBenchmark; +import jenkins.benchmark.jmh.JmhBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import java.util.Objects; +/** + * Sample benchmark without doing anything special to the Jenkins instance. + */ @JmhBenchmark public class JmhStateBenchmark { public static class MyState extends JmhBenchmarkState { From c950cffeb0906ad0ef50f81fd6d4ca2f3b0b27c7 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Tue, 4 Jun 2019 16:43:38 +0530 Subject: [PATCH 13/59] Add documentation to use the benchmarks --- docs/jmh-benchmarks.adoc | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 docs/jmh-benchmarks.adoc diff --git a/docs/jmh-benchmarks.adoc b/docs/jmh-benchmarks.adoc new file mode 100644 index 000000000..c9b2c0587 --- /dev/null +++ b/docs/jmh-benchmarks.adoc @@ -0,0 +1,64 @@ += JMH benchmarks with Jenkins + +link:https://openjdk.java.net/projects/code-tools/jmh/[Java Microbenchmark Harness] allows running benchmarks +in the JVM. To run a benchmark where you need a Jenkins instance, you can use use link:../src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java[``JmhBenchmarkState``] +as a state in your benchmark. This creates a temporary Jenkins instance for each fork of the JMH benchmark. + +== Writing benchmarks + +A reference to the Jenkins instance is available through either the `JmhBenchmarkState#getJenkins()` or through +`Jenkins.getInstance()` like you would otherwise do. `JmhBenchmarkState` provides `setup()` and `tearDown` methods +which can be overridden to configure the Jenkins instance according to your benchmark's requirements. +You can also configure the instance using https://jenkins.io/projects/jcasc/[Jenkins Configuration as Code] by extending +`CascJmhBenchmarkState` instead of `JmhBenchmarkState` and overriding the `getResourcePath()` method and returning the +path to where your YAML configuration is located. + +== Running the benchmarks + +The benchmarks can be run through JUnit tests. From a test method, you can use the `OptionsBuilder` provided by JMH to +configure your benchmarks. For a sample, take a look at link:../src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java[this]. +Classes containing benchmarks are found automatically by the `BenchmarkFinder` when annotated +with `@JmhBenchmark`. Benchmark reports can also be generated and can be visualized using the jmh-report plugin. + +NOTE: Benchmark methods need to be annotated by `@Benchmark` for JMH to detect them. + +== Sample benchmarks + +=== Simplest Benchmark: + +[source,java] +---- +@JmhBenchmark +public class JmhStateBenchmark { + public static class MyState extends JmhBenchmarkState { + } + + @Benchmark + public void benchmark(MyState state) { + // benchmark code goes here + } +} +---- + +=== Using Configuration as code: + +Instead of extending `JmhBenchmarkState`, use `CascJmhBenchmarkState` +[source,java] +---- +public static class MyState extends CascJmhBenchmarkState { + @Nonnull + @Override + protected String getResourcePath() { + return "path/to/config.yaml"; + } +} +---- + +If you override the `setup()` method of `CascJmhBenchmarkState`, make sure to call `super.setup()` so that +configuration as code works as intended. + +=== Other benchmarks + +Some benchmarks have been implemented in the https://github.com/jenkinsci/role-strategy-plugin/tree/master/src/test/java/jmh/benchmarks[Role Strategy Plugin] +which show setting up the benchmarks for many different situations. + From e44da54597aef74891817e6e2eb249c13aa0fd80 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 13:28:23 +0530 Subject: [PATCH 14/59] Revert Configuration as Code for now See: https://groups.google.com/forum/#!topic/jenkinsci-dev/cgbYEB3c_Vc --- docs/jmh-benchmarks.adoc | 20 -------- .../benchmark/jmh/JmhBenchmarkState.java | 5 +- .../jmh/casc/CascJmhBenchmarkState.java | 48 ------------------- .../jmh/samples/CascStateBenchmark.java | 30 ------------ src/test/resources/sample-config.yaml | 3 -- 5 files changed, 1 insertion(+), 105 deletions(-) delete mode 100644 src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java delete mode 100644 src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java delete mode 100644 src/test/resources/sample-config.yaml diff --git a/docs/jmh-benchmarks.adoc b/docs/jmh-benchmarks.adoc index c9b2c0587..df4e156ac 100644 --- a/docs/jmh-benchmarks.adoc +++ b/docs/jmh-benchmarks.adoc @@ -9,9 +9,6 @@ as a state in your benchmark. This creates a temporary Jenkins instance for each A reference to the Jenkins instance is available through either the `JmhBenchmarkState#getJenkins()` or through `Jenkins.getInstance()` like you would otherwise do. `JmhBenchmarkState` provides `setup()` and `tearDown` methods which can be overridden to configure the Jenkins instance according to your benchmark's requirements. -You can also configure the instance using https://jenkins.io/projects/jcasc/[Jenkins Configuration as Code] by extending -`CascJmhBenchmarkState` instead of `JmhBenchmarkState` and overriding the `getResourcePath()` method and returning the -path to where your YAML configuration is located. == Running the benchmarks @@ -40,23 +37,6 @@ public class JmhStateBenchmark { } ---- -=== Using Configuration as code: - -Instead of extending `JmhBenchmarkState`, use `CascJmhBenchmarkState` -[source,java] ----- -public static class MyState extends CascJmhBenchmarkState { - @Nonnull - @Override - protected String getResourcePath() { - return "path/to/config.yaml"; - } -} ----- - -If you override the `setup()` method of `CascJmhBenchmarkState`, make sure to call `super.setup()` so that -configuration as code works as intended. - === Other benchmarks Some benchmarks have been implemented in the https://github.com/jenkinsci/role-strategy-plugin/tree/master/src/test/java/jmh/benchmarks[Role Strategy Plugin] diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index dc6a90aab..038f2307d 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -3,7 +3,6 @@ import hudson.model.Hudson; import hudson.model.RootAction; import hudson.security.ACL; -import jenkins.benchmark.jmh.casc.CascJmhBenchmarkState; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import org.apache.commons.lang3.mutable.MutableInt; @@ -29,13 +28,11 @@ *

* To use a Jenkins instance in your benchmark, your class containing benchmarks should have a public static inner * class that extends this class and should be annotated with {@link JmhBenchmark} to allow it to be automatically - * discovered by {@link BenchmarkFinder}. To configure the instance, use {@link #setup()} or use - * {@link CascJmhBenchmarkState}. + * discovered by {@link BenchmarkFinder}. To configure the instance, use {@link #setup()}. * * @see #setup() * @see #tearDown() * @see BenchmarkFinder - * @see CascJmhBenchmarkState * @since TODO */ @State(Scope.Benchmark) diff --git a/src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java deleted file mode 100644 index 53565d593..000000000 --- a/src/main/java/jenkins/benchmark/jmh/casc/CascJmhBenchmarkState.java +++ /dev/null @@ -1,48 +0,0 @@ -package jenkins.benchmark.jmh.casc; - -import io.jenkins.plugins.casc.ConfigurationAsCode; -import io.jenkins.plugins.casc.ConfiguratorException; -import jenkins.benchmark.jmh.JmhBenchmarkState; - -import javax.annotation.Nonnull; -import java.util.Objects; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Use Configuration as Code to setup the Jenkins instance for JMH benchmark. - *

- * Override the {@code getResourcePath} method configure the path to the YAML configuration. - * - * @see JmhBenchmarkState - */ -@SuppressWarnings("unused") -public abstract class CascJmhBenchmarkState extends JmhBenchmarkState { - private static final Logger LOGGER = Logger.getLogger(CascJmhBenchmarkState.class.getName()); - - /** - * Location of the YAML file to be used for configuration-as-code - * - * @return String containing the location of YAML file in the classpath - */ - @Nonnull - protected abstract String getResourcePath(); - - /** - * Setups the Jenkins instance using configuration as code - * available through the {@link CascJmhBenchmarkState#getResourcePath()}. - * - * @throws ConfiguratorException when unable to configure - */ - @Override - public void setup() throws Exception { - String config = Objects.requireNonNull(getClass().getClassLoader().getResource(getResourcePath())).toExternalForm(); - try { - ConfigurationAsCode.get().configure(config); - } catch (ConfiguratorException e) { - LOGGER.log(Level.SEVERE, "Unable to configure using configuration as code. Aborting."); - terminateJenkins(); - throw e; // causes JMH to abort benchmark - } - } -} diff --git a/src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java b/src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java deleted file mode 100644 index af89cd6e2..000000000 --- a/src/test/java/jenkins/benchmark/jmh/samples/CascStateBenchmark.java +++ /dev/null @@ -1,30 +0,0 @@ -package jenkins.benchmark.jmh.samples; - -import jenkins.benchmark.jmh.casc.CascJmhBenchmarkState; -import jenkins.benchmark.jmh.JmhBenchmark; -import org.openjdk.jmh.annotations.Benchmark; - -import javax.annotation.Nonnull; - -import static org.junit.Assert.assertEquals; - -/** - * Sample benchmark configuring Jenkins instance using Configuration as Code - */ -@JmhBenchmark -public class CascStateBenchmark { - public static class MyState extends CascJmhBenchmarkState { - @Nonnull - @Override - protected String getResourcePath() { - return "sample-config.yaml"; - } - } - - @Benchmark - public void benchmark(MyState state) { - assertEquals(state.getJenkins().getSystemMessage(), - "Benchmark started with Configuration as Code"); - assertEquals(state.getJenkins().getNumExecutors(), 22); - } -} diff --git a/src/test/resources/sample-config.yaml b/src/test/resources/sample-config.yaml deleted file mode 100644 index e9878fdbe..000000000 --- a/src/test/resources/sample-config.yaml +++ /dev/null @@ -1,3 +0,0 @@ -jenkins: - systemMessage: "Benchmark started with Configuration as Code" - numExecutors: 22 From 8ea80428836b1f115085f6b7c6f2531d850acee4 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 13:33:48 +0530 Subject: [PATCH 15/59] Update documentation --- docs/jmh-benchmarks.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/jmh-benchmarks.adoc b/docs/jmh-benchmarks.adoc index df4e156ac..9add3e004 100644 --- a/docs/jmh-benchmarks.adoc +++ b/docs/jmh-benchmarks.adoc @@ -1,5 +1,7 @@ = JMH benchmarks with Jenkins +:toc: + link:https://openjdk.java.net/projects/code-tools/jmh/[Java Microbenchmark Harness] allows running benchmarks in the JVM. To run a benchmark where you need a Jenkins instance, you can use use link:../src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java[``JmhBenchmarkState``] as a state in your benchmark. This creates a temporary Jenkins instance for each fork of the JMH benchmark. @@ -37,7 +39,7 @@ public class JmhStateBenchmark { } ---- -=== Other benchmarks +=== Examples Some benchmarks have been implemented in the https://github.com/jenkinsci/role-strategy-plugin/tree/master/src/test/java/jmh/benchmarks[Role Strategy Plugin] which show setting up the benchmarks for many different situations. From fe51bf0327d742b6380c8e77aa3a8f9461981a7d Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 13:49:39 +0530 Subject: [PATCH 16/59] Update jmh-benchmarks.adoc --- docs/jmh-benchmarks.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/jmh-benchmarks.adoc b/docs/jmh-benchmarks.adoc index 9add3e004..1242de895 100644 --- a/docs/jmh-benchmarks.adoc +++ b/docs/jmh-benchmarks.adoc @@ -1,5 +1,4 @@ = JMH benchmarks with Jenkins - :toc: link:https://openjdk.java.net/projects/code-tools/jmh/[Java Microbenchmark Harness] allows running benchmarks From 356774047c1161c31d1c597c0c8ea5173c104240 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 19:41:28 +0530 Subject: [PATCH 17/59] Remove CASC dependency from pom --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 5cde548f9..fe1e03093 100644 --- a/pom.xml +++ b/pom.xml @@ -181,12 +181,6 @@ THE SOFTWARE. reflections 0.9.11 - - io.jenkins - configuration-as-code - 1.19 - true - From 587b275d29f565023b0aa7e74b3b1f0c6c11cfad Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 21:05:20 +0530 Subject: [PATCH 18/59] Update JavaDocs and keep backward compatibility --- .../benchmark/jmh/JmhBenchmarkState.java | 2 +- .../org/jvnet/hudson/test/JenkinsRule.java | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index 038f2307d..a7ef869b9 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -87,7 +87,7 @@ public final void terminateJenkins() { private void launchInstance() throws Exception { ImmutablePair results = JenkinsRule._createWebServer(contextPath, localPort::setValue, - this::getJenkinsURL, getClass().getClassLoader()); + this::getJenkinsURL, getClass().getClassLoader(), JenkinsRule::_configureUserRealm); server = results.left; ServletContext webServer = results.right; diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 968d39910..2efc9cf80 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -427,6 +427,8 @@ public void before() throws Throwable { /** * Configures the update center setting for the test. * By default, we load updates from local proxy to avoid network traffic as much as possible. + * @param jenkins the instance to configure + * @since TODO */ public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { jenkins.setNoUsageStatistics(true); // collecting usage stats from tests is pointless. @@ -695,7 +697,7 @@ protected ServletContext createWebServer() throws Exception { LOGGER.log(Level.SEVERE, "Unable to get Url", e); return null; } - }, getClass().getClassLoader()); + }, getClass().getClassLoader(), this::configureUserRealm); server = results.left; return results.right; } @@ -703,14 +705,17 @@ protected ServletContext createWebServer() throws Exception { /** * Creates a web server on which Jenkins can run * - * @param contextPath the context path at which to put Jenkins - * @param portSetter the port on which the server runs will be set using this function - * @param urlGetter returns the URL after the port has been set using portSetter - * @param classLoader the class loader for the {@link WebAppContext} + * @param contextPath the context path at which to put Jenkins + * @param portSetter the port on which the server runs will be set using this function + * @param urlGetter returns the URL after the port has been set using portSetter + * @param classLoader the class loader for the {@link WebAppContext} + * @param loginServiceSupplier configures the {@link LoginService} for the instance * @return ImmutablePair consisting of the {@link Server} and the {@link ServletContext} + * @since TODO */ public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, - Supplier urlGetter, ClassLoader classLoader) + Supplier urlGetter, ClassLoader classLoader, + Supplier loginServiceSupplier) throws Exception { Server server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { public Thread newThread(Runnable r) { @@ -726,7 +731,7 @@ public Thread newThread(Runnable r) { context.addBean(new NoListenerConfiguration(context)); server.setHandler(context); context.setMimeTypes(MIME_TYPES); - context.getSecurityHandler().setLoginService(_configureUserRealm()); + context.getSecurityHandler().setLoginService(loginServiceSupplier.get()); context.setResourceBase(WarExploder.getExplodedDir().getPath()); ServerConnector connector = new ServerConnector(server, 1, 1); @@ -754,6 +759,13 @@ protected LoginService configureUserRealm() { return _configureUserRealm(); } + /** + * Creates a {@link HashLoginService} with three users: alice, bob and charlie + * + * The password is same as the username + * @return a new login service + * @since TODO + */ public static LoginService _configureUserRealm() { HashLoginService realm = new HashLoginService(); realm.setName("default"); // this is the magic realm name to make it effective on everywhere @@ -2169,7 +2181,7 @@ public WebResponse loadWebResponse(final WebRequest webRequest) throws IOExcepti public WebClient login(String username, String password) throws Exception { return login(username,password,false); } - + /** * Returns {@code true} if JavaScript is enabled and the script engine was loaded successfully. * Short-hand method to ease discovery of feature + improve readability From 0849d76c1314c7ec9df7e9da44da4d74b512bd0c Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 7 Jun 2019 21:14:26 +0530 Subject: [PATCH 19/59] Add @since TODO Co-Authored-By: Oleg Nenashev --- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 2efc9cf80..916eca13d 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -516,6 +516,7 @@ public void after() throws Exception { * @param server server on which Jenkins is running. * @param tearDowns tear down methods for tests * @param jenkins the jenkins instance + * @since TODO */ public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { jettyLevel(Level.WARNING); From d591189fccf754cd852d7a944a7b055fc820fe65 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Mon, 10 Jun 2019 08:16:34 +0530 Subject: [PATCH 20/59] Bring back `configureUpdateCenter` --- .../benchmark/jmh/JmhBenchmarkState.java | 1 + .../org/jvnet/hudson/test/JenkinsRule.java | 39 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index a7ef869b9..345d9b4cc 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -94,6 +94,7 @@ private void launchInstance() throws Exception { jenkins = new Hudson(temporaryDirectoryAllocator.allocate(), webServer); JenkinsRule._configureJenkinsForTest(jenkins); + JenkinsRule._configureUpdateCenter(jenkins); jenkins.getActions().add(this); Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(Objects.requireNonNull(getJenkinsURL()).toString()); diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 916eca13d..c59bc11e5 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -416,6 +416,7 @@ public void before() throws Throwable { jenkins.setCrumbIssuer(new TestCrumbIssuer()); // TODO: Move to _configureJenkinsForTest after JENKINS-55240 _configureJenkinsForTest(jenkins); + configureUpdateCenter(); // expose the test instance as a part of URL tree. // this allows tests to use a part of the URL space for itself. @@ -425,9 +426,10 @@ public void before() throws Throwable { } /** - * Configures the update center setting for the test. - * By default, we load updates from local proxy to avoid network traffic as much as possible. - * @param jenkins the instance to configure + * Configures a Jenkins instance for test. + * + * @param jenkins jenkins instance which has to be configured + * @throws Exception if unable to configure * @since TODO */ public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { @@ -438,7 +440,30 @@ public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { // set a default JDK to be the one that the harness is using. jenkins.getJDKs().add(new JDK("default", System.getProperty("java.home"))); + } + + private static void dumpThreads() { + ThreadInfo[] threadInfos = Functions.getThreadInfos(); + Functions.ThreadGroupMap m = Functions.sortThreadsAndGetGroupMap(threadInfos); + for (ThreadInfo ti : threadInfos) { + System.err.println(Functions.dumpThreadInfo(ti, m)); + } + } + /** + * Configures the update center setting for the test. + * By default, we load updates from local proxy to avoid network traffic as much as possible. + */ + protected void configureUpdateCenter() throws Exception { + _configureUpdateCenter(jenkins); + } + + /** + * Internal method used to configure update center to avoid network traffic. + * @param jenkins the Jenkins to configure + * @since TODO + */ + public static void _configureUpdateCenter(Jenkins jenkins) throws Exception { final String updateCenterUrl; jettyLevel(Level.WARNING); try { @@ -455,14 +480,6 @@ public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { sites.clear(); sites.add(new UpdateSite("default", updateCenterUrl)); } - - private static void dumpThreads() { - ThreadInfo[] threadInfos = Functions.getThreadInfos(); - Functions.ThreadGroupMap m = Functions.sortThreadsAndGetGroupMap(threadInfos); - for (ThreadInfo ti : threadInfos) { - System.err.println(Functions.dumpThreadInfo(ti, m)); - } - } /** * Override to tear down your specific external resource. From 320034a034a45a80012476514ffdd44ff7fe6bac Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Wed, 12 Jun 2019 12:43:51 -0700 Subject: [PATCH 21/59] Switch to SpotBugs --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0825d86a9..91822c976 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ THE SOFTWARE. org.jenkins-ci jenkins - 1.51 + 1.52 @@ -152,9 +152,9 @@ THE SOFTWARE. RELEASE72 - com.github.stephenc.findbugs - findbugs-annotations - 1.3.9-1 + com.github.spotbugs + spotbugs-annotations + true org.jenkins-ci From a209d44d2da3d2bdcfc4d38ef7a0b15bc1ffa766 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 12 Jun 2019 17:06:51 -0400 Subject: [PATCH 22/59] Avoid printing duplicated messages when LoggerRule is used. --- src/main/java/org/jvnet/hudson/test/LoggerRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jvnet/hudson/test/LoggerRule.java b/src/main/java/org/jvnet/hudson/test/LoggerRule.java index 7f6dddfe6..8927e39c9 100644 --- a/src/main/java/org/jvnet/hudson/test/LoggerRule.java +++ b/src/main/java/org/jvnet/hudson/test/LoggerRule.java @@ -68,7 +68,7 @@ public class LoggerRule extends ExternalResource { */ public LoggerRule() { consoleHandler.setFormatter(new DeltaSupportLogFormatter()); - consoleHandler.setLevel(Level.ALL); + consoleHandler.setLevel(Level.WARNING); // do not duplicate messages from the console handler associated with the root logger } /** From d47538e4a2ab5d0dc40dab5b69a9c351d52395c5 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 12 Jun 2019 17:44:15 -0400 Subject: [PATCH 23/59] Deleting MilliSecLogFormatter. --- .../hudson/test/MilliSecLogFormatter.java | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/main/java/org/jvnet/hudson/test/MilliSecLogFormatter.java diff --git a/src/main/java/org/jvnet/hudson/test/MilliSecLogFormatter.java b/src/main/java/org/jvnet/hudson/test/MilliSecLogFormatter.java deleted file mode 100644 index 4ad536d23..000000000 --- a/src/main/java/org/jvnet/hudson/test/MilliSecLogFormatter.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.jvnet.hudson.test; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Date; -import java.util.logging.Formatter; -import java.util.logging.LogRecord; - -/** - * {@link Formatter} that prints out milliseconds. - * - * Useful when one needs to understand sub-second timing issues. - * - * @author Kohsuke Kawaguchi - */ -public class MilliSecLogFormatter extends Formatter { - private final Date dat = new Date(); - - public synchronized String format(LogRecord record) { - dat.setTime(record.getMillis()); - String source; - if (record.getSourceClassName() != null) { - source = record.getSourceClassName(); - if (record.getSourceMethodName() != null) { - source += " " + record.getSourceMethodName(); - } - } else { - source = record.getLoggerName(); - } - String message = formatMessage(record); - String throwable = ""; - if (record.getThrown() != null) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.println(); - record.getThrown().printStackTrace(pw); - pw.close(); - throwable = sw.toString(); - } - return String.format("%1$tl:%1$tM:%1$tS.%1$tL %1$Tp %2$s%n%4$s: %5$s%6$s%n", - dat, - source, - record.getLoggerName(), - record.getLevel().getLocalizedName(), - message, - throwable); - } -} From 998d75d3bccaa96a41ebcead31f1d0e9e09ff4b0 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Thu, 13 Jun 2019 09:19:54 +0530 Subject: [PATCH 24/59] Cleanup error handling in JenkinsRule.java --- .../benchmark/jmh/JmhBenchmarkState.java | 15 ++++++----- .../org/jvnet/hudson/test/JenkinsRule.java | 25 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index 345d9b4cc..6bae5e8c8 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -18,6 +18,7 @@ import javax.annotation.CheckForNull; import javax.servlet.ServletContext; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; import java.util.Objects; import java.util.logging.Level; @@ -87,7 +88,7 @@ public final void terminateJenkins() { private void launchInstance() throws Exception { ImmutablePair results = JenkinsRule._createWebServer(contextPath, localPort::setValue, - this::getJenkinsURL, getClass().getClassLoader(), JenkinsRule::_configureUserRealm); + getClass().getClassLoader(), JenkinsRule::_configureUserRealm); server = results.left; ServletContext webServer = results.right; @@ -97,15 +98,13 @@ private void launchInstance() throws Exception { JenkinsRule._configureUpdateCenter(jenkins); jenkins.getActions().add(this); - Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(Objects.requireNonNull(getJenkinsURL()).toString()); + String url = Objects.requireNonNull(getJenkinsURL()).toString(); + Objects.requireNonNull(JenkinsLocationConfiguration.get()).setUrl(url); + LOGGER.log(Level.INFO, "Running on {0}", url); } - private URL getJenkinsURL() { - try { - return new URL("http://localhost:" + localPort.getValue() + contextPath + "/"); - } catch (Exception e) { - return null; - } + private URL getJenkinsURL() throws MalformedURLException { + return new URL("http://localhost:" + localPort.getValue() + contextPath + "/"); } /** diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index c59bc11e5..82ea354ec 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -536,11 +536,13 @@ public void after() throws Exception { * @since TODO */ public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { + final RuntimeException exception = new RuntimeException(); + jettyLevel(Level.WARNING); try { server.stop(); } catch (Exception e) { - // ignore + exception.addSuppressed(e); } finally { jettyLevel(Level.INFO); } @@ -550,7 +552,7 @@ public static void _stopJenkins(Server server, List tearDowns, try { r.run(); } catch (Exception e) { - // ignore + exception.addSuppressed(e); } } } @@ -559,6 +561,10 @@ public static void _stopJenkins(Server server, List tearDowns, jenkins.cleanUp(); ExtensionList.clearLegacyInstances(); DescriptorExtensionList.clearLegacyInstances(); + + if (exception.getSuppressed().length > 0) { + throw exception; + } } private static void jettyLevel(Level level) { @@ -708,15 +714,10 @@ public File getWebAppRoot() throws Exception { * that we need for testing. */ protected ServletContext createWebServer() throws Exception { - ImmutablePair results = _createWebServer(contextPath, (x) -> localPort = x, () -> { - try { - return getURL(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Unable to get Url", e); - return null; - } - }, getClass().getClassLoader(), this::configureUserRealm); + ImmutablePair results = _createWebServer(contextPath, + (x) -> localPort = x, getClass().getClassLoader(), this::configureUserRealm); server = results.left; + LOGGER.log(Level.INFO, "Running on {0}", getURL()); return results.right; } @@ -725,14 +726,13 @@ protected ServletContext createWebServer() throws Exception { * * @param contextPath the context path at which to put Jenkins * @param portSetter the port on which the server runs will be set using this function - * @param urlGetter returns the URL after the port has been set using portSetter * @param classLoader the class loader for the {@link WebAppContext} * @param loginServiceSupplier configures the {@link LoginService} for the instance * @return ImmutablePair consisting of the {@link Server} and the {@link ServletContext} * @since TODO */ public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, - Supplier urlGetter, ClassLoader classLoader, + ClassLoader classLoader, Supplier loginServiceSupplier) throws Exception { Server server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { @@ -764,7 +764,6 @@ public Thread newThread(Runnable r) { server.start(); portSetter.accept(connector.getLocalPort()); - LOGGER.log(Level.INFO, "Running on {0}", urlGetter.get()); ServletContext servletContext = context.getServletContext(); return new ImmutablePair<>(server, servletContext); From 982716894bfd4e30247eba5c30b54025151f415e Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Thu, 13 Jun 2019 10:34:43 +0530 Subject: [PATCH 25/59] Resolve undetected merge conflict --- src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java | 2 +- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index 6bae5e8c8..7b262f636 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -88,7 +88,7 @@ public final void terminateJenkins() { private void launchInstance() throws Exception { ImmutablePair results = JenkinsRule._createWebServer(contextPath, localPort::setValue, - getClass().getClassLoader(), JenkinsRule::_configureUserRealm); + getClass().getClassLoader(), localPort.getValue(), JenkinsRule::_configureUserRealm); server = results.left; ServletContext webServer = results.right; diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 2838aa7fb..02ba5f099 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -715,7 +715,7 @@ public File getWebAppRoot() throws Exception { */ protected ServletContext createWebServer() throws Exception { ImmutablePair results = _createWebServer(contextPath, - (x) -> localPort = x, getClass().getClassLoader(), this::configureUserRealm); + (x) -> localPort = x, getClass().getClassLoader(), localPort, this::configureUserRealm); server = results.left; LOGGER.log(Level.INFO, "Running on {0}", getURL()); return results.right; @@ -727,12 +727,13 @@ protected ServletContext createWebServer() throws Exception { * @param contextPath the context path at which to put Jenkins * @param portSetter the port on which the server runs will be set using this function * @param classLoader the class loader for the {@link WebAppContext} + * @param localPort port on which the server runs * @param loginServiceSupplier configures the {@link LoginService} for the instance * @return ImmutablePair consisting of the {@link Server} and the {@link ServletContext} * @since TODO */ public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, - ClassLoader classLoader, + ClassLoader classLoader, int localPort, Supplier loginServiceSupplier) throws Exception { Server server = new Server(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { From 60313c9564ac0688ad73d229fcc5e432fc27eb27 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Thu, 13 Jun 2019 18:46:13 +0530 Subject: [PATCH 26/59] Add message to RuntimeException in JenkinsRule#_stopJenkins --- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 02ba5f099..7ac7aa943 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -536,7 +536,7 @@ public void after() throws Exception { * @since TODO */ public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { - final RuntimeException exception = new RuntimeException(); + final RuntimeException exception = new RuntimeException("One or more problems while shutting down Jenkins"); jettyLevel(Level.WARNING); try { From a66df371785282136a0df967b30b1abf92e4474e Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 13 Jun 2019 22:08:28 +0200 Subject: [PATCH 27/59] [maven-release-plugin] prepare release jenkins-test-harness-2.50 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 81d7e7575..b80909dfd 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.50 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.50 From fbc5346894309a6a1aa52c2e56e25b651a66b2cf Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 13 Jun 2019 22:09:03 +0200 Subject: [PATCH 28/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b80909dfd..77f27064b 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.50 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.50 + ${scmTag} - 2.50 + 2.51 -SNAPSHOT UTF-8 9.4.5.v20170502 From 3f1c4e075ab19f714976db20cd6864a36fb21d18 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Fri, 14 Jun 2019 13:59:41 +0530 Subject: [PATCH 29/59] Update @since TODO in JavaDocs --- .../java/jenkins/benchmark/jmh/BenchmarkFinder.java | 2 +- src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java | 2 +- .../java/jenkins/benchmark/jmh/JmhBenchmarkState.java | 2 +- .../java/org/jvnet/hudson/test/JenkinsMatchers.java | 6 +++--- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java index 2bebebdf8..5662bfb14 100644 --- a/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java +++ b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java @@ -8,7 +8,7 @@ /** * Find classes annotated with {@link JmhBenchmark} to run their benchmark methods. - * @since TODO + * @since 2.50 */ public final class BenchmarkFinder { final private String[] packageName; diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java index 1da307ec2..791867c11 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java @@ -7,7 +7,7 @@ /** * Annotate your benchmark classes with this annotation to allow them to be discovered by {@link BenchmarkFinder} - * @since TODO + * @since 2.50 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java index 7b262f636..28ccb90ed 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmarkState.java @@ -34,7 +34,7 @@ * @see #setup() * @see #tearDown() * @see BenchmarkFinder - * @since TODO + * @since 2.50 */ @State(Scope.Benchmark) public abstract class JmhBenchmarkState implements RootAction { diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java b/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java index 672e9d576..d368955a4 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsMatchers.java @@ -399,7 +399,7 @@ public void describeTo(Description description) { /** * Returns a Matcher for the plain text value of a Secret. - * @since TODO + * @since 2.50 */ public static Matcher hasPlainText(Matcher matcher) { return new HasPlainText(matcher); @@ -407,7 +407,7 @@ public static Matcher hasPlainText(Matcher matcher) { /** * Returns a Matcher for the plain text value of a Secret. - * @since TODO + * @since 2.50 */ public static Matcher hasPlainText(String expected) { return new HasPlainText(CoreMatchers.equalTo(expected)); @@ -426,7 +426,7 @@ protected String featureValueOf(Secret actual) { /** * Returns a Matcher that matches against the given pattern using {@link java.util.regex.Matcher#find()}. - * @since TODO + * @since 2.50 */ public static Matcher matchesPattern(String pattern) { return new MatchesPattern(Pattern.compile(pattern)); diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 7ac7aa943..0ae7c18f4 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -430,7 +430,7 @@ public void before() throws Throwable { * * @param jenkins jenkins instance which has to be configured * @throws Exception if unable to configure - * @since TODO + * @since 2.50 */ public static void _configureJenkinsForTest(Jenkins jenkins) throws Exception { jenkins.setNoUsageStatistics(true); // collecting usage stats from tests is pointless. @@ -461,7 +461,7 @@ protected void configureUpdateCenter() throws Exception { /** * Internal method used to configure update center to avoid network traffic. * @param jenkins the Jenkins to configure - * @since TODO + * @since 2.50 */ public static void _configureUpdateCenter(Jenkins jenkins) throws Exception { final String updateCenterUrl; @@ -533,7 +533,7 @@ public void after() throws Exception { * @param server server on which Jenkins is running. * @param tearDowns tear down methods for tests * @param jenkins the jenkins instance - * @since TODO + * @since 2.50 */ public static void _stopJenkins(Server server, List tearDowns, Jenkins jenkins) { final RuntimeException exception = new RuntimeException("One or more problems while shutting down Jenkins"); @@ -730,7 +730,7 @@ protected ServletContext createWebServer() throws Exception { * @param localPort port on which the server runs * @param loginServiceSupplier configures the {@link LoginService} for the instance * @return ImmutablePair consisting of the {@link Server} and the {@link ServletContext} - * @since TODO + * @since 2.50 */ public static ImmutablePair _createWebServer(String contextPath, Consumer portSetter, ClassLoader classLoader, int localPort, @@ -785,7 +785,7 @@ protected LoginService configureUserRealm() { * * The password is same as the username * @return a new login service - * @since TODO + * @since 2.50 */ public static LoginService _configureUserRealm() { HashLoginService realm = new HashLoginService(); From ca561b8d6a9ff914db3c2726a5c59209a25d1654 Mon Sep 17 00:00:00 2001 From: Abhyudaya Sharma Date: Tue, 18 Jun 2019 10:33:05 +0530 Subject: [PATCH 30/59] [JENKINS-58038] Use Annotation-Indexer instead of Reflections (#141) * Use ClassGraph instead of Reflections Reflections was causing a dependency conflict with the Guava from Jenkins Core (see: https://travis-ci.org/jenkinsci/configuration-as-code-plugin/jobs/546110907#L878) * Use SezPoz instead of ClassGraph * Use annotation-indexer as suggested by @jglick * Make it BenchmarkFinder's constructor public --- pom.xml | 5 --- .../benchmark/jmh/BenchmarkFinder.java | 32 +++++++++---------- .../jenkins/benchmark/jmh/JmhBenchmark.java | 4 +++ .../jenkins/benchmark/jmh/BenchmarkTest.java | 6 ++-- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index 77f27064b..094206272 100644 --- a/pom.xml +++ b/pom.xml @@ -176,11 +176,6 @@ THE SOFTWARE. jmh-generator-annprocess 1.21 - - org.reflections - reflections - 0.9.11 - diff --git a/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java index 5662bfb14..e4c4d3169 100644 --- a/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java +++ b/src/main/java/jenkins/benchmark/jmh/BenchmarkFinder.java @@ -1,25 +1,28 @@ package jenkins.benchmark.jmh; + +import org.jvnet.hudson.annotation_indexer.Index; import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; -import org.reflections.Reflections; -import java.util.Objects; -import java.util.Set; +import java.io.IOException; +import java.lang.reflect.AnnotatedElement; /** * Find classes annotated with {@link JmhBenchmark} to run their benchmark methods. + * * @since 2.50 */ +@SuppressWarnings("WeakerAccess") public final class BenchmarkFinder { - final private String[] packageName; + private final ClassLoader classLoader; /** - * Creates a {@link BenchmarkFinder} + * Class whose {@link ClassLoader} will be used to search for benchmarks. * - * @param packageNames find benchmarks in these packages + * @param clazz the class whose {@link ClassLoader} will be used to search for benchmarks. */ - public BenchmarkFinder(String... packageNames) { - this.packageName = packageNames; + public BenchmarkFinder(Class clazz) { + this.classLoader = clazz.getClassLoader(); } /** @@ -27,14 +30,11 @@ public BenchmarkFinder(String... packageNames) { * * @param optionsBuilder the optionsBuilder used to build the benchmarks */ - public void findBenchmarks(ChainedOptionsBuilder optionsBuilder) { - Reflections reflections = new Reflections((Object[]) packageName); - Set> benchmarkClasses = reflections.getTypesAnnotatedWith(JmhBenchmark.class); - benchmarkClasses.forEach(clazz -> { + public void findBenchmarks(ChainedOptionsBuilder optionsBuilder) throws IOException { + for (AnnotatedElement e : Index.list(JmhBenchmark.class, classLoader)) { + Class clazz = (Class) e; JmhBenchmark annotation = clazz.getAnnotation(JmhBenchmark.class); - if (Objects.nonNull(annotation)) { - optionsBuilder.include(clazz.getName() + annotation.value()); - } - }); + optionsBuilder.include(clazz.getName() + annotation.value()); + } } } diff --git a/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java index 791867c11..3b3f23af9 100644 --- a/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java +++ b/src/main/java/jenkins/benchmark/jmh/JmhBenchmark.java @@ -1,5 +1,7 @@ package jenkins.benchmark.jmh; +import org.jvnet.hudson.annotation_indexer.Indexed; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -7,10 +9,12 @@ /** * Annotate your benchmark classes with this annotation to allow them to be discovered by {@link BenchmarkFinder} + * * @since 2.50 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) +@Indexed public @interface JmhBenchmark { /** * Methods which annotated by {@link org.openjdk.jmh.annotations.Benchmark} diff --git a/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java b/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java index 532a4efb3..2c637234f 100644 --- a/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java +++ b/src/test/java/jenkins/benchmark/jmh/BenchmarkTest.java @@ -26,16 +26,14 @@ public void testJmhBenchmarks() throws Exception { ChainedOptionsBuilder optionsBuilder = new OptionsBuilder() .forks(1) - .warmupIterations(1) - .warmupBatchSize(1) + .warmupIterations(0) .measurementIterations(1) .measurementBatchSize(1) .shouldFailOnError(true) .result("target/jmh-reports/jmh-benchmark-report.json") .timeUnit(TimeUnit.MICROSECONDS) .resultFormat(ResultFormatType.JSON); - BenchmarkFinder finder = new BenchmarkFinder(this.getClass().getPackage().getName()); - finder.findBenchmarks(optionsBuilder); + new BenchmarkFinder(getClass()).findBenchmarks(optionsBuilder); new Runner(optionsBuilder.build()).run(); } } From 9579aa2a0176d1c80cce5740bf2d41ff5fd7fd0d Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 18 Jun 2019 07:11:29 +0200 Subject: [PATCH 31/59] Move changelogs to GitHub releases --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 04115b73d..47543e614 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Jenkins Unit Test Harness + +[![GitHub release](https://img.shields.io/github/release/jenkinsci/jenkins-test-harness.svg?label=release)](https://github.com/jenkinsci/jenkins-test-harness/releases/latest) + Defines test harness for Jenkins core and plugins that you can use during the `mvn test` phase. See [wiki page](//wiki.jenkins-ci.org/display/JENKINS/Unit+Test) @@ -8,6 +11,13 @@ See https://javadoc.jenkins.io/component/jenkins-test-harness/ ## Changelog +| WARNING: Changelogs have been moved to [GitHub Releases](https://github.com/jenkinsci/jenkins-test-harness/releases) | +| --- | + +## New releases + +See [GitHub Releases](https://github.com/jenkinsci/jenkins-test-harness/releases). + ### 2.49 (2019 Apr 02) * [PR-127](https://github.com/jenkinsci/jenkins-test-harness/pull/127): `JenkinsRule.showAgentLogs` utility From 320fd121b2c3ace33784ed78e5c3a0b376ce4cba Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 18 Jun 2019 08:31:09 +0200 Subject: [PATCH 32/59] [maven-release-plugin] prepare release jenkins-test-harness-2.51 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 094206272..966c1ef6a 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.51 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.51 From 3f11e2d537a71c6d423829b3764157d561043632 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 18 Jun 2019 08:31:39 +0200 Subject: [PATCH 33/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 966c1ef6a..090fbcb76 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.51 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.51 + ${scmTag} - 2.51 + 2.52 -SNAPSHOT UTF-8 9.4.5.v20170502 From 9224f8cb30bc40c15ab09453230bb090f93db521 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Mon, 1 Jul 2019 14:38:03 +0200 Subject: [PATCH 34/59] Add a failing test --- .../org/jvnet/hudson/test/LoggerRuleTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java b/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java index 355b1f70e..01b5ea6a9 100644 --- a/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java +++ b/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java @@ -32,6 +32,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.jvnet.hudson.test.LoggerRule.recorded; @@ -83,4 +84,38 @@ public void testRecordedNoShortCircuit() { assertThat(logRule, recorded(Level.INFO, equalTo("Foo Entry"), instanceOf(IllegalStateException.class))); assertThat(logRule, recorded(Level.INFO, equalTo("Foo Entry"), instanceOf(IOException.class))); } + + private boolean active; + + @Test + public void multipleThreads() throws InterruptedException { + active = true; + logRule.record("Foo", Level.INFO).capture(1000); + Thread thread = new Thread("logging stuff") { + @Override + public void run() { + try { + int i = 1; + while (active) { + FOO_LOGGER.log(Level.INFO, "Foo Entry " + i++); + Thread.sleep(50); + } + } catch (InterruptedException x) { + // stopped + } + } + }; + try { + thread.setDaemon(true); + thread.start(); + Thread.sleep(500); + for (String message : logRule.getMessages()) { + assertNotNull(message); + Thread.sleep(50); + } + } finally { + active = false; + thread.interrupt(); + } + } } From 27255d31d3c9ade9f27c77c915567fa644ada18f Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Mon, 1 Jul 2019 14:38:15 +0200 Subject: [PATCH 35/59] Fix concurrent access to LoggerRule#getMessages --- src/main/java/org/jvnet/hudson/test/LoggerRule.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jvnet/hudson/test/LoggerRule.java b/src/main/java/org/jvnet/hudson/test/LoggerRule.java index 8927e39c9..8e2350964 100644 --- a/src/main/java/org/jvnet/hudson/test/LoggerRule.java +++ b/src/main/java/org/jvnet/hudson/test/LoggerRule.java @@ -26,6 +26,7 @@ import hudson.util.RingBufferLogHandler; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -78,7 +79,7 @@ public LoggerRule() { * @return this rule, for convenience */ public LoggerRule capture(int maximum) { - messages = new ArrayList(); + messages = Collections.synchronizedList(new ArrayList<>()); ringHandler = new RingBufferLogHandler(maximum) { final Formatter f = new SimpleFormatter(); // placeholder instance for what should have been a static method perhaps @Override @@ -153,12 +154,16 @@ public List getRecords() { } /** + * Returns a read-only view of current messages. + * * {@link Formatter#formatMessage} applied to {@link #getRecords} at the time of logging. * However, if the message is null, but there is an exception, {@link Throwable#toString} will be used. * Does not include logger names, stack traces, times, etc. (these will appear in the test console anyway). */ public List getMessages() { - return messages; + synchronized (messages) { + return Collections.unmodifiableList(new ArrayList<>(messages)); + } } @Override From 29592f92d95275c3067c7a7d45976e88304b6e0a Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Mon, 1 Jul 2019 16:16:19 +0200 Subject: [PATCH 36/59] Reviews from Jesse --- src/main/java/org/jvnet/hudson/test/LoggerRule.java | 6 ++++-- src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java | 9 ++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jvnet/hudson/test/LoggerRule.java b/src/main/java/org/jvnet/hudson/test/LoggerRule.java index 8e2350964..8af013aa4 100644 --- a/src/main/java/org/jvnet/hudson/test/LoggerRule.java +++ b/src/main/java/org/jvnet/hudson/test/LoggerRule.java @@ -79,7 +79,7 @@ public LoggerRule() { * @return this rule, for convenience */ public LoggerRule capture(int maximum) { - messages = Collections.synchronizedList(new ArrayList<>()); + messages = new ArrayList<>(); ringHandler = new RingBufferLogHandler(maximum) { final Formatter f = new SimpleFormatter(); // placeholder instance for what should have been a static method perhaps @Override @@ -87,7 +87,9 @@ public synchronized void publish(LogRecord record) { super.publish(record); String message = f.formatMessage(record); Throwable x = record.getThrown(); - messages.add(message == null && x != null ? x.toString() : message); + synchronized (messages) { + messages.add(message == null && x != null ? x.toString() : message); + } } }; ringHandler.setLevel(Level.ALL); diff --git a/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java b/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java index 01b5ea6a9..745b95270 100644 --- a/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java +++ b/src/test/java/org/jvnet/hudson/test/LoggerRuleTest.java @@ -24,6 +24,7 @@ package org.jvnet.hudson.test; import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.Test; @@ -85,18 +86,16 @@ public void testRecordedNoShortCircuit() { assertThat(logRule, recorded(Level.INFO, equalTo("Foo Entry"), instanceOf(IOException.class))); } - private boolean active; - @Test public void multipleThreads() throws InterruptedException { - active = true; + AtomicBoolean active = new AtomicBoolean(true); logRule.record("Foo", Level.INFO).capture(1000); Thread thread = new Thread("logging stuff") { @Override public void run() { try { int i = 1; - while (active) { + while (active.get()) { FOO_LOGGER.log(Level.INFO, "Foo Entry " + i++); Thread.sleep(50); } @@ -114,7 +113,7 @@ public void run() { Thread.sleep(50); } } finally { - active = false; + active.set(false); thread.interrupt(); } } From 738c1a9f3a55be849c0a06795c0a1ae6f5177873 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 1 Jul 2019 15:57:14 -0400 Subject: [PATCH 37/59] Reverting #138 as it broke display of FINE- messages. --- src/main/java/org/jvnet/hudson/test/LoggerRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jvnet/hudson/test/LoggerRule.java b/src/main/java/org/jvnet/hudson/test/LoggerRule.java index 8927e39c9..7f6dddfe6 100644 --- a/src/main/java/org/jvnet/hudson/test/LoggerRule.java +++ b/src/main/java/org/jvnet/hudson/test/LoggerRule.java @@ -68,7 +68,7 @@ public class LoggerRule extends ExternalResource { */ public LoggerRule() { consoleHandler.setFormatter(new DeltaSupportLogFormatter()); - consoleHandler.setLevel(Level.WARNING); // do not duplicate messages from the console handler associated with the root logger + consoleHandler.setLevel(Level.ALL); } /** From 9ee559182336385c6054955e800d84f620bb0ceb Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 1 Jul 2019 16:19:26 -0400 Subject: [PATCH 38/59] [maven-release-plugin] prepare release jenkins-test-harness-2.52 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 090fbcb76..7e046820a 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.52 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.52 From 4c4b23f33901f1716ff27deb332860e2517f58ab Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 1 Jul 2019 16:19:44 -0400 Subject: [PATCH 39/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7e046820a..e4377271c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.52 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.52 + ${scmTag} - 2.52 + 2.53 -SNAPSHOT UTF-8 9.4.5.v20170502 From 239a28580a51d10e0d97a716e6a6718704adaa4c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 5 Jul 2019 10:07:26 -0400 Subject: [PATCH 40/59] Create ${TestPluginManager.rootDir}/${artifactId}.jpl, not the.jpl. --- .../org/jvnet/hudson/test/TestPluginManager.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jvnet/hudson/test/TestPluginManager.java b/src/main/java/org/jvnet/hudson/test/TestPluginManager.java index ee82c5637..796965453 100644 --- a/src/main/java/org/jvnet/hudson/test/TestPluginManager.java +++ b/src/main/java/org/jvnet/hudson/test/TestPluginManager.java @@ -32,6 +32,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.URISyntaxException; @@ -40,6 +41,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; +import java.util.jar.Manifest; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; @@ -104,8 +106,15 @@ private Set loadBundledPlugins(File fromDir) throws IOException, URISynt u = getClass().getClassLoader().getResource("the.hpl"); // keep backward compatible } if (u!=null) try { - names.add("the.jpl"); - copyBundledPlugin(u, "the.jpl"); + String thisPlugin; + try (InputStream is = u.openStream()) { + thisPlugin = new Manifest(is).getMainAttributes().getValue("Short-Name"); + } + if (thisPlugin == null) { + throw new IOException("malformed " + u); + } + names.add(thisPlugin + ".jpl"); + copyBundledPlugin(u, thisPlugin + ".jpl"); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Failed to copy the.jpl",e); } @@ -133,6 +142,7 @@ private Set loadBundledPlugins(File fromDir) throws IOException, URISynt throw new IOException(index + " contains bogus line " + line, x); } } + // TODO should this be running names.add(line + ".jpi")? Affects PluginWrapper.isBundled & .*Dependents if(f.exists()){ copyBundledPlugin(url, line + ".jpi"); }else{ From bc6d3c9806f8ff1adfc04b684b34337c6763734a Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 10 Jul 2019 14:04:43 -0400 Subject: [PATCH 41/59] [maven-release-plugin] prepare release jenkins-test-harness-2.53 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e4377271c..685bb4955 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.53 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.53 From 494b89c8df0bbe58c9c77392d84d6d9aafb6ceca Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 10 Jul 2019 14:05:02 -0400 Subject: [PATCH 42/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 685bb4955..d381b48bc 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.53 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.53 + ${scmTag} - 2.53 + 2.54 -SNAPSHOT UTF-8 9.4.5.v20170502 From e971153dc64661a9462cff21b0daea99464d3393 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Sat, 20 Jul 2019 12:21:01 -0700 Subject: [PATCH 43/59] Enable Enforcer checks --- pom.xml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d381b48bc..18ee3ecc4 100644 --- a/pom.xml +++ b/pom.xml @@ -53,9 +53,6 @@ THE SOFTWARE. 9.4.5.v20170502 8 1 - - - true false @@ -190,6 +187,25 @@ THE SOFTWARE. true + + org.apache.maven.plugins + maven-enforcer-plugin + + + + + + com.google.guava:guava + + + + + org.apache.maven.plugins maven-surefire-plugin From e5921c20d4b20c9abea080e38c665bbfe98ca45f Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Mon, 22 Jul 2019 11:31:08 -0700 Subject: [PATCH 44/59] Remove usages of deprecated edu.umd.cs.findbugs.annotations.SuppressWarnings --- src/main/java/org/jvnet/hudson/test/MemoryAssert.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jvnet/hudson/test/MemoryAssert.java b/src/main/java/org/jvnet/hudson/test/MemoryAssert.java index 46ae1143b..e7ad22f16 100644 --- a/src/main/java/org/jvnet/hudson/test/MemoryAssert.java +++ b/src/main/java/org/jvnet/hudson/test/MemoryAssert.java @@ -24,7 +24,7 @@ package org.jvnet.hudson.test; -import edu.umd.cs.findbugs.annotations.SuppressWarnings; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.util.VersionNumber; import java.lang.ref.Reference; import java.lang.ref.SoftReference; @@ -156,7 +156,7 @@ public static void assertGC(WeakReference reference) { * @param allowSoft if true, pass even if {@link SoftReference}s apparently needed to be cleared by forcing an {@link OutOfMemoryError}; * if false, fail in such a case (though the failure will be slow) */ - @SuppressWarnings("DLS_DEAD_LOCAL_STORE_OF_NULL") + @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE_OF_NULL") public static void assertGC(WeakReference reference, boolean allowSoft) { // Disabled on Java 9+, because below will call Netbeans Insane Engine, which in turns tries to call setAccessible /* TODO version-number 1.6+: From 5bc69635562c3604cc8f0f8c14fae4d88d443df8 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 23 Jul 2019 13:20:35 -0400 Subject: [PATCH 45/59] Fixing showAgentLogs. --- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 0ae7c18f4..3d728e432 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -224,6 +224,7 @@ import java.net.HttpURLConnection; import java.nio.channels.ClosedByInterruptException; +import java.util.LinkedList; import java.util.concurrent.ExecutionException; import java.util.logging.ConsoleHandler; import java.util.logging.Formatter; @@ -1091,6 +1092,8 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable loggers; private final TaskListener stderr = StreamTaskListener.fromStderr(); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private static final List loggerReferences = new LinkedList<>(); RemoteLogDumper(String name, Map loggers) { this.name = name; this.loggers = loggers; @@ -1101,6 +1104,7 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable Date: Tue, 23 Jul 2019 13:58:51 -0400 Subject: [PATCH 46/59] Also align clocks on master and agent. --- .../org/jvnet/hudson/test/DeltaSupportLogFormatter.java | 6 +++--- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jvnet/hudson/test/DeltaSupportLogFormatter.java b/src/main/java/org/jvnet/hudson/test/DeltaSupportLogFormatter.java index 318187642..917cb6255 100644 --- a/src/main/java/org/jvnet/hudson/test/DeltaSupportLogFormatter.java +++ b/src/main/java/org/jvnet/hudson/test/DeltaSupportLogFormatter.java @@ -29,13 +29,13 @@ class DeltaSupportLogFormatter extends SupportLogFormatter { - private static long start = System.nanoTime(); + static long start = System.currentTimeMillis(); static String elapsedTime() { - return String.format("%8.3f", (System.nanoTime() - start) / 1_000_000_000.0); + return String.format("%8.3f", (System.currentTimeMillis() - start) / 1_000.0); } DeltaSupportLogFormatter() { - start = System.nanoTime(); // reset for each test, if using LoggerRule + start = System.currentTimeMillis(); // reset for each test, if using LoggerRule } @Override protected String formatTime(LogRecord record) { diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 3d728e432..137b2ac71 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -1092,6 +1092,7 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable loggers; private final TaskListener stderr = StreamTaskListener.fromStderr(); + private final long start = DeltaSupportLogFormatter.start; @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private static final List loggerReferences = new LinkedList<>(); RemoteLogDumper(String name, Map loggers) { @@ -1117,6 +1118,7 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable Date: Tue, 23 Jul 2019 14:02:41 -0400 Subject: [PATCH 47/59] Nicer formatting: put [remote] notation after timestamp. --- src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 137b2ac71..42fde9266 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -1104,7 +1104,7 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable Date: Tue, 23 Jul 2019 15:37:26 -0400 Subject: [PATCH 48/59] [maven-release-plugin] prepare release jenkins-test-harness-2.54 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 18ee3ecc4..3ca146525 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.54 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.54 From 048426cd84d4ee810452b0dde1dc5a910257e23c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 23 Jul 2019 15:37:44 -0400 Subject: [PATCH 49/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 3ca146525..2d5383716 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.54 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.54 + ${scmTag} - 2.54 + 2.55 -SNAPSHOT UTF-8 9.4.5.v20170502 From 3bc892fb688d4d37207d61ede9213445ff26b83a Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 25 Jul 2019 11:56:31 +0200 Subject: [PATCH 50/59] Enable Dependabot in the repository --- .dependabot/config.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .dependabot/config.yml diff --git a/.dependabot/config.yml b/.dependabot/config.yml new file mode 100644 index 000000000..d4efc1d98 --- /dev/null +++ b/.dependabot/config.yml @@ -0,0 +1,19 @@ +version: 1 +update_configs: +- package_manager: "java:maven" + directory: "/" + update_schedule: "weekly" + default_reviewers: + - "oleg-nenashev" + - "jglick" + ignored_updates: + - match: + dependency_name: "org.jenkins-ci.main:jenkins-core" + - match: + dependency_name: "org.jenkins-ci.main:jenkins-war" + # Avoid bumping plugins for self-testing, there is PCT which shoud be used for newest versions + - match: + dependency_name: "org.jenkins-ci.plugins*" + - match: + dependency_name: "io.jenkins.plugins*" + #TBD: Jetty? From 04987e82891e65d27626b125e9ea0a2172c20ee3 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 26 Jul 2019 08:12:35 +0200 Subject: [PATCH 51/59] Dependabot: Fix typo in the YAML syntax --- .dependabot/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dependabot/config.yml b/.dependabot/config.yml index d4efc1d98..082bd2d64 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -9,7 +9,7 @@ update_configs: ignored_updates: - match: dependency_name: "org.jenkins-ci.main:jenkins-core" - - match: + - match: dependency_name: "org.jenkins-ci.main:jenkins-war" # Avoid bumping plugins for self-testing, there is PCT which shoud be used for newest versions - match: From 819033d05b7068c18aef78b41ffcf6c3a2e2e2b5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2019 06:20:14 +0000 Subject: [PATCH 52/59] Bump ant from 1.8.0 to 1.10.6 Bumps ant from 1.8.0 to 1.10.6. Signed-off-by: dependabot-preview[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d5383716..bcd87c1d1 100644 --- a/pom.xml +++ b/pom.xml @@ -244,7 +244,7 @@ THE SOFTWARE. org.apache.ant ant - 1.8.0 + 1.10.6 From b4ee5950fd0b57b138aa64da735f8f6724766097 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2019 06:20:26 +0000 Subject: [PATCH 53/59] Bump org-netbeans-insane from RELEASE72 to RELEASE802 Bumps org-netbeans-insane from RELEASE72 to RELEASE802. Signed-off-by: dependabot-preview[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d5383716..239cb4e54 100644 --- a/pom.xml +++ b/pom.xml @@ -145,7 +145,7 @@ THE SOFTWARE. org.netbeans.modules org-netbeans-insane - RELEASE72 + RELEASE802 com.github.spotbugs From 6d9e2316180e4d8a79568a54d66de0cb143f597e Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Mon, 29 Jul 2019 11:45:04 -0700 Subject: [PATCH 54/59] Remove unnecessary dependency on ant-launcher --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index e719dce65..28979c311 100644 --- a/pom.xml +++ b/pom.xml @@ -246,12 +246,6 @@ THE SOFTWARE. ant 1.10.6 - - - org.apache.ant - ant-launcher - 1.8.0 - org.codehaus.gmaven.runtime gmaven-runtime-2.0 From bd70ca6956396c5260696499dd35ebdbe36f8782 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Mon, 29 Jul 2019 12:33:33 -0700 Subject: [PATCH 55/59] Switch from GMaven to GMavenPlus --- pom.xml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index e719dce65..0524cd5fb 100644 --- a/pom.xml +++ b/pom.xml @@ -225,9 +225,9 @@ THE SOFTWARE. - org.codehaus.gmaven - gmaven-plugin - + org.codehaus.gmavenplus + gmavenplus-plugin + 1.7.1 preset-packager @@ -236,7 +236,9 @@ THE SOFTWARE. execute - ${pom.basedir}/src/main/preset-data/package.groovy + + + @@ -252,15 +254,7 @@ THE SOFTWARE. ant-launcher 1.8.0 - - org.codehaus.gmaven.runtime - gmaven-runtime-2.0 - 1.5-jenkins-1 - - - 2.0 - From 00aeaf0297a083a45546e48e8a0d53136138f95a Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Tue, 6 Aug 2019 14:54:50 -0700 Subject: [PATCH 56/59] Fix Oleg's bad merge --- pom.xml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pom.xml b/pom.xml index 663157788..033ed9bed 100644 --- a/pom.xml +++ b/pom.xml @@ -248,17 +248,6 @@ THE SOFTWARE. ant 1.10.6 - - - org.apache.ant - ant-launcher - 1.8.0 - - - org.codehaus.gmaven.runtime - gmaven-runtime-2.0 - 1.5-jenkins-1 - From dbdd2bc9bc9be38605a5d4a169ff12e2176b2882 Mon Sep 17 00:00:00 2001 From: "A. Jard" Date: Wed, 7 Aug 2019 14:27:02 +0200 Subject: [PATCH 57/59] [JENKINS-58571] Fix default value for `isNameEditable()` on MockFolder. (#159) * [JENKINS-58571] fix default value for isNameEditable on MockFolder. * [JENKINS-58571] waiting for next LTS to uncomment override --- src/main/java/org/jvnet/hudson/test/MockFolder.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/jvnet/hudson/test/MockFolder.java b/src/main/java/org/jvnet/hudson/test/MockFolder.java index d2c0ac97b..5e2e9e083 100644 --- a/src/main/java/org/jvnet/hudson/test/MockFolder.java +++ b/src/main/java/org/jvnet/hudson/test/MockFolder.java @@ -270,4 +270,11 @@ public TopLevelItem getJob(String name) { return new MockFolder(parent, name); } } + + /* TODO uncomment when core dep ≥ 2.110: + @Override + */ + public boolean isNameEditable() { + return true; + } } From 06ad680b901204e54f43e28df33ac1812ffc07fa Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 12 Aug 2019 15:07:50 +0200 Subject: [PATCH 58/59] [maven-release-plugin] prepare release jenkins-test-harness-2.55 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 033ed9bed..628f2885d 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - ${revision}${changelist} + 2.55 Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,7 +43,7 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - ${scmTag} + jenkins-test-harness-2.55 From e10ad3fe19a3c8a722400217d64162a03d97ac77 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 12 Aug 2019 15:08:26 +0200 Subject: [PATCH 59/59] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 628f2885d..09909be3c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-test-harness - 2.55 + ${revision}${changelist} Test harness for Jenkins and plugins Harness used to run functional tests of Jenkins core and plugins. @@ -43,11 +43,11 @@ THE SOFTWARE. scm:git:git://github.com/jenkinsci/${project.artifactId}.git scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}.git https://github.com/jenkinsci/${project.artifactId} - jenkins-test-harness-2.55 + ${scmTag} - 2.55 + 2.56 -SNAPSHOT UTF-8 9.4.5.v20170502