Skip to content

Commit

Permalink
[JENKINS-72387] Provide JUnit5 Class (static) context for JenkinsRule (
Browse files Browse the repository at this point in the history
  • Loading branch information
bstopp committed Nov 29, 2023
1 parent 5514089 commit 0d2b4aa
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package org.jvnet.hudson.test.junit.jupiter;

import edu.umd.cs.findbugs.annotations.NonNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.runner.Description;
import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule;
Expand All @@ -12,18 +13,18 @@
* Provides JUnit 5 compatibility for {@link JenkinsRule}.
*/
class JUnit5JenkinsRule extends JenkinsRule {
private final ParameterContext context;

JUnit5JenkinsRule(@NonNull ParameterContext context, @NonNull ExtensionContext extensionContext) {
this.context = context;
JUnit5JenkinsRule(@NonNull ExtensionContext extensionContext, Annotation... annotations) {
this.testDescription = Description.createTestDescription(
extensionContext.getTestClass().map(Class::getName).orElse(null),
extensionContext.getTestMethod().map(Method::getName).orElse(null));
extensionContext.getTestClass().map(Class::getName).orElse(null),
extensionContext.getTestMethod().map(Method::getName).orElse(null),
annotations);
}

@Override
public void recipe() throws Exception {
JenkinsRecipe jenkinsRecipe = context.findAnnotation(JenkinsRecipe.class).orElse(null);
final JenkinsRecipe jenkinsRecipe = this.testDescription.getAnnotation(JenkinsRecipe.class);

if (jenkinsRecipe == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,76 @@
package org.jvnet.hudson.test.junit.jupiter;

import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.*;
import org.junit.platform.commons.support.HierarchyTraversalMode;
import org.junit.platform.commons.support.ModifierSupport;
import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule;

import java.lang.reflect.Field;
import java.util.function.Function;
import java.util.function.Predicate;

import static org.junit.platform.commons.support.ReflectionSupport.findFields;

/**
* JUnit 5 extension providing {@link JenkinsRule} integration.
*
* @see WithJenkins
*/
class JenkinsExtension implements ParameterResolver, AfterEachCallback {
class JenkinsExtension implements BeforeAllCallback, AfterAllCallback, ParameterResolver, AfterEachCallback {

private static final String KEY = "jenkins-instance";
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(JenkinsExtension.class);

@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
Class<?> clazz = extensionContext.getRequiredTestClass();
Predicate<Field> predicate = (field -> ModifierSupport.isStatic(field)
&& JenkinsRule.class.isAssignableFrom(field.getType()));
Field field = findFields(clazz, predicate, HierarchyTraversalMode.BOTTOM_UP).stream()
.findFirst()
.orElse(null);
if (field == null) {
return;
}

final JenkinsRecipe recipe = field.getDeclaredAnnotation(JenkinsRecipe.class);
final JenkinsRule rule;
if (recipe != null) {
rule = new JUnit5JenkinsRule(extensionContext, recipe);
} else {
rule = new JUnit5JenkinsRule(extensionContext);
}
extensionContext
.getStore(NAMESPACE)
.getOrComputeIfAbsent(KEY, key -> rule, JenkinsRule.class);
try {
rule.before();
} catch (Throwable e) {
throw new ExtensionContextException(e.getMessage(), e);
}
field.setAccessible(true);
field.set(null, rule);
}

@Override
public void afterAll(ExtensionContext extensionContext) throws Exception {
Class<?> clazz = extensionContext.getRequiredTestClass();
Predicate<Field> predicate = (field -> ModifierSupport.isStatic(field)
&& JenkinsRule.class.isAssignableFrom(field.getType()));
Field field = findFields(clazz, predicate, HierarchyTraversalMode.BOTTOM_UP).stream()
.findFirst()
.orElse(null);
if (field != null) {
final JenkinsRule rule =
extensionContext.getStore(NAMESPACE).get(KEY, JenkinsRule.class);
if (rule == null) {
return;
}
rule.after();
}
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
final JenkinsRule rule = context.getStore(NAMESPACE).remove(KEY, JenkinsRule.class);
Expand All @@ -33,13 +87,18 @@ public boolean supportsParameter(ParameterContext parameterContext, ExtensionCon

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
JenkinsRecipe recipe = parameterContext.findAnnotation(JenkinsRecipe.class).orElse(null);
Function<String, JenkinsRule> compute;
if (recipe == null) {
compute = key -> new JUnit5JenkinsRule(extensionContext);
} else {
compute = key -> new JUnit5JenkinsRule(extensionContext, recipe);
}

final JenkinsRule rule =
extensionContext
.getStore(NAMESPACE)
.getOrComputeIfAbsent(
KEY,
key -> new JUnit5JenkinsRule(parameterContext, extensionContext),
JenkinsRule.class);
.getOrComputeIfAbsent(KEY, compute, JenkinsRule.class);

try {
rule.before();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.jvnet.hudson.test.junit.jupiter;

import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.IOException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.collection.IsEmptyCollection.empty;

@WithJenkins
class JenkinsRuleClassResolverTest {

static JenkinsRule rule;

@Test
void jenkinsRuleIsAccessible() throws IOException {
assertThat(rule.jenkins.getJobNames(), empty());
rule.createFreeStyleProject("job-0");
assertThat(rule.jenkins.getJobNames(), hasSize(1));
}
}

0 comments on commit 0d2b4aa

Please sign in to comment.