Skip to content

Commit

Permalink
Introduce a HookOrder annotation to order hooks (#521)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtnord committed Apr 11, 2023
1 parent 2e05ec6 commit eb32afe
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/main/java/org/jenkins/tools/test/model/hook/HookOrder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jenkins.tools.test.model.hook;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Relative order to sort hooks in.
* The higher the number the higher priority the hook has.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface HookOrder {

int order() default 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.jenkins.tools.test.model.hook;

import java.io.Serializable;
import java.util.Comparator;

/**
* Comparator that will order first based on the {@link HookOrder}.
* Objects whose classes are missing the annotation order will be treated as if they have the default order.
* Where two objects have the same order sorting will occur based on the classname.
* This {@link Comparator} is not {@code null} safe.
*/
public class HookOrderComparator implements Comparator<Object>, Serializable {

private static final long serialVersionUID = 1L;

@Override
public int compare(Object left, Object right) {
int leftOrder = getHookOrder(left);
int rightOrder = getHookOrder(right);
if (leftOrder < rightOrder) {
return 1;
}
if (leftOrder > rightOrder) {
return -1;
}
return left.getClass().getName().compareTo(right.getClass().getName());
}

private static int getHookOrder(Object obj) {
HookOrder hookOrder = obj.getClass().getDeclaredAnnotation(HookOrder.class);
return hookOrder == null ? 0 : hookOrder.order();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -99,7 +98,7 @@ private List<PluginCompatTesterHook<StageContext>> findHooks(
for (PluginCompatTesterHook<? extends StageContext> hook : ServiceLoader.load(clazz, classLoader)) {
sortedHooks.add((PluginCompatTesterHook<StageContext>) hook);
}
sortedHooks.sort(Comparator.comparing(hook -> hook.getClass().getName()));
sortedHooks.sort(new HookOrderComparator());
return sortedHooks;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package org.jenkins.tools.test.model.hook;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.comparator.ComparatorMatcherBuilder.comparedBy;

import java.util.ArrayList;
import java.util.List;
import org.hamcrest.collection.IsIterableContainingInOrder;
import org.junit.jupiter.api.Test;

class HookOrderComparatorTest {

@Test
void testIndividual() {
HookOrderComparator hookOrderComparator = new HookOrderComparator();

assertThat(new AlphaNoPriority(), comparedBy(hookOrderComparator).lessThan(new AlphaLowPriority()));
assertThat(new AlphaNoPriority(), comparedBy(hookOrderComparator).greaterThan(new AlphaHighPriority()));

assertThat(new AlphaNoPriority(), comparedBy(hookOrderComparator).lessThan(new BetaNoPriority()));
assertThat(new AlphaNoPriority(), comparedBy(hookOrderComparator).lessThan(new GammaLowPriority()));

assertThat(new AlphaNoPriority(), comparedBy(hookOrderComparator).comparesEqualTo(new AlphaNoPriority()));
}

@Test
void testOrdering() {
HookOrderComparator hookOrderComparator = new HookOrderComparator();
List<?> priorityList;

// annotation only
priorityList = toSortedList(
new AlphaLowPriority(),
new AlphaHighPriority(),
new BetaLowPriority(),
new BetaHighPriority(),
new GammaLowPriority(),
new GammaHighPriority());
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new GammaHighPriority(),
new BetaHighPriority(),
new AlphaHighPriority(),
new AlphaLowPriority(),
new BetaLowPriority(),
new GammaLowPriority()));
// sort is stable
priorityList.sort(hookOrderComparator);
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new GammaHighPriority(),
new BetaHighPriority(),
new AlphaHighPriority(),
new AlphaLowPriority(),
new BetaLowPriority(),
new GammaLowPriority()));

// no annotation - classname only
priorityList = toSortedList(new GammaNoPriority(), new AlphaNoPriority(), new BetaNoPriority());
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new AlphaNoPriority(), new BetaNoPriority(), new GammaNoPriority()));
// sort is stable
priorityList.sort(hookOrderComparator);
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new AlphaNoPriority(), new BetaNoPriority(), new GammaNoPriority()));

// mix of annotation and no annotation
priorityList = toSortedList(new AlphaHighPriority(), new BetaLowPriority(), new GammaNoPriority());
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new AlphaHighPriority(), new GammaNoPriority(), new BetaLowPriority()));
// sort is stable
priorityList.sort(hookOrderComparator);
assertThat(
priorityList,
IsIterableContainingInOrder.contains(
new AlphaHighPriority(), new GammaNoPriority(), new BetaLowPriority()));

// With Colliding annotations
priorityList = toSortedList(new GammaHighPriority(), new DeltaCollidingHighPriority());
assertThat(
priorityList,
IsIterableContainingInOrder.contains(new DeltaCollidingHighPriority(), new GammaHighPriority()));
// sort is stable
priorityList.sort(hookOrderComparator);
assertThat(
priorityList,
IsIterableContainingInOrder.contains(new DeltaCollidingHighPriority(), new GammaHighPriority()));
}

static class Base {
@Override
public int hashCode() {
return this.getClass().hashCode();
}

@Override
public boolean equals(Object arg0) {
return this.getClass().equals(arg0.getClass());
}

@Override
public String toString() {
return this.getClass().getSimpleName();
}
}

private List<Object> toSortedList(Object... objects) {
List<Object> l = new ArrayList<>(List.of(objects));
l.sort(new HookOrderComparator());
return l;
}

@HookOrder(order = -10)
static class AlphaLowPriority extends Base {}

static class AlphaNoPriority extends Base {}

@HookOrder(order = 10)
static class AlphaHighPriority extends Base {}

@HookOrder(order = -20)
static class BetaLowPriority extends Base {}

static class BetaNoPriority extends Base {}

@HookOrder(order = 20)
static class BetaHighPriority extends Base {}

@HookOrder(order = -30)
static class GammaLowPriority extends Base {}

static class GammaNoPriority extends Base {}

@HookOrder(order = 30)
static class GammaHighPriority extends Base {}

@HookOrder(order = 30)
static class DeltaCollidingHighPriority extends Base {}
}

0 comments on commit eb32afe

Please sign in to comment.