Skip to content

Commit

Permalink
Add support for @ShouldNotPin/@ShouldPin on superclass
Browse files Browse the repository at this point in the history
Fix for quarkusio#41782
Allow the usage of @ShouldPin and @ShouldNotPin on super classes
  • Loading branch information
bdeneuter authored and barreiro committed Jul 23, 2024
1 parent 4c42530 commit f723171
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 34 deletions.
9 changes: 9 additions & 0 deletions independent-projects/junit5-virtual-threads/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<impsort-maven-plugin.version>1.11.0</impsort-maven-plugin.version>

<junit.jupiter.version>5.10.3</junit.jupiter.version>
<junit.testkit.version>1.10.3</junit.testkit.version>
<assertj.version>3.26.3</assertj.version>
</properties>

Expand All @@ -57,6 +58,11 @@
<scope>compile</scope>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-testkit</artifactId>
<version>${junit.testkit.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
Expand Down Expand Up @@ -135,6 +141,9 @@
<!-- set tmpdir as early as possible because failsafe sets it too late for JDK16 -->
<argLine>-Djava.io.tmpdir="${project.build.directory}"</argLine>
<excludedEnvironmentVariables>MAVEN_OPTS</excludedEnvironmentVariables>
<excludes>
<exclude>io.quarkus.test.junit5.virtual.internal.ignore.**Test.java</exclude>
</excludes>
</configuration>
</plugin>
<!-- Replicate what's in parent, since this pom doesn't inherit parent but IDE settings will be common -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.test.junit5.virtual;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Expand All @@ -12,6 +13,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Inherited
public @interface ShouldNotPin {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.test.junit5.virtual;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Expand All @@ -12,6 +13,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Inherited
public @interface ShouldPin {
int atMost() default Integer.MAX_VALUE;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.quarkus.test.junit5.virtual.internal;

import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
import static org.junit.platform.testkit.engine.EventConditions.*;

import org.assertj.core.api.Condition;
import org.junit.platform.testkit.engine.EngineTestKit;
import org.junit.platform.testkit.engine.Events;

public class JUnitEngine {

public static void runTestAndAssertFailure(Class<?> clazz, String methodName, String message) {
runTest(clazz, methodName).assertThatEvents()
.haveExactly(1, event(test(methodName),
finishedWithFailure(new Condition<>(
throwable -> throwable instanceof AssertionError && throwable.getMessage().contains(message),
""))));
}

public static void runTestAndAssertSuccess(Class<?> clazz, String methodName) {
runTest(clazz, methodName).assertThatEvents()
.haveExactly(1, event(test(methodName),
finishedSuccessfully()));
}

public static Events runTest(Class<?> clazz, String methodName) {
return EngineTestKit
.engine("junit-jupiter")
.selectors(selectMethod(clazz, methodName))
.execute()
.testEvents();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.test.junit5.virtual.internal;

import static io.quarkus.test.junit5.virtual.internal.JUnitEngine.runTestAndAssertFailure;
import static io.quarkus.test.junit5.virtual.internal.JUnitEngine.runTestAndAssertSuccess;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleOnMethodTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldNotPinOnClassTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldNotPinOnSuperClassTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldPinOnSuperClassTest;

public class ShouldNotPinTest {

@ParameterizedTest
@MethodSource
@EnabledForJreRange(min = JRE.JAVA_21)
void testShouldNotPinButPinEventDetected(Class<?> clazz, String methodName) {
runTestAndAssertFailure(clazz, methodName, "was expected to NOT pin the carrier thread");
}

public static Stream<Arguments> testShouldNotPinButPinEventDetected() {
return Stream.of(
arguments(LoomUnitExampleOnMethodTest.class, "failWhenShouldNotPinAndPinDetected"),
arguments(LoomUnitExampleOnMethodTest.class, "failWhenShouldNotPinAtMostAndTooManyPinDetected"),
arguments(LoomUnitExampleShouldNotPinOnClassTest.class, "failWhenShouldNotPinAndPinDetected"),
arguments(LoomUnitExampleShouldNotPinOnSuperClassTest.class, "failWhenShouldNotPinAndPinDetected"),
arguments(LoomUnitExampleShouldPinOnSuperClassTest.class, "failWhenShouldNotPinAndPinDetected"));
}

@Test
@EnabledForJreRange(min = JRE.JAVA_21)
void shouldNotPinOnMethodOverridesClassAnnotation() {
runTestAndAssertSuccess(LoomUnitExampleShouldNotPinOnClassTest.class, "overrideClassAnnotation");
runTestAndAssertSuccess(LoomUnitExampleShouldNotPinOnSuperClassTest.class, "overrideClassAnnotation");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.quarkus.test.junit5.virtual.internal;

import static io.quarkus.test.junit5.virtual.internal.JUnitEngine.runTestAndAssertFailure;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.util.stream.Stream;

import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleOnMethodTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldNotPinOnClassTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldNotPinOnSuperClassTest;
import io.quarkus.test.junit5.virtual.internal.ignore.LoomUnitExampleShouldPinOnSuperClassTest;

public class ShouldPinTest {

@ParameterizedTest
@MethodSource
@EnabledForJreRange(min = JRE.JAVA_21)
void testShouldPinButNoPinEventDetected(Class<?> clazz, String methodName) {
runTestAndAssertFailure(clazz, methodName, "was expected to pin the carrier thread, it didn't");
}

public static Stream<Arguments> testShouldPinButNoPinEventDetected() {
return Stream.of(
arguments(LoomUnitExampleOnMethodTest.class, "failWhenMethodShouldPinButNoPinDetected"),
arguments(LoomUnitExampleShouldNotPinOnClassTest.class, "failWhenMethodShouldPinButNoPinDetected"),
arguments(LoomUnitExampleShouldNotPinOnSuperClassTest.class, "failWhenShouldPinAndNoPinDetected"),
arguments(LoomUnitExampleShouldPinOnSuperClassTest.class, "failWhenShouldPinAndNoPinDetected"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public TestPinJfrEvent(String message) {
this.message = message;
}

static void pin() {
public static void pin() {
TestPinJfrEvent event = new TestPinJfrEvent("Hello, JFR!");
event.commit();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit5.virtual.ShouldNotPin;
import io.quarkus.test.junit5.virtual.ShouldPin;
import io.quarkus.test.junit5.virtual.VirtualThreadUnit;
import io.quarkus.test.junit5.virtual.internal.TestPinJfrEvent;

@VirtualThreadUnit
public class LoomUnitExampleOnMethodTest {

@Test
@ShouldNotPin
void failWhenShouldNotPinAndPinDetected() {
TestPinJfrEvent.pin();
}

@Test
@ShouldNotPin(atMost = 1)
void failWhenShouldNotPinAtMostAndTooManyPinDetected() {
TestPinJfrEvent.pin();
TestPinJfrEvent.pin();
}

@Test
@ShouldPin
void failWhenMethodShouldPinButNoPinDetected() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit5.virtual.ShouldNotPin;
import io.quarkus.test.junit5.virtual.ShouldPin;
import io.quarkus.test.junit5.virtual.VirtualThreadUnit;
import io.quarkus.test.junit5.virtual.internal.TestPinJfrEvent;

@VirtualThreadUnit
@ShouldNotPin // You can use @ShouldNotPin or @ShouldPin on the class itself, it's applied to each method.
public class LoomUnitExampleShouldNotPinOnClassTest {

@Test
public void failWhenShouldNotPinAndPinDetected() {
TestPinJfrEvent.pin();
}

@Test
@ShouldPin(atMost = 1)
public void overrideClassAnnotation() {
TestPinJfrEvent.pin();
}

@Test
@ShouldPin
public void failWhenMethodShouldPinButNoPinDetected() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import io.quarkus.test.junit5.virtual.ShouldNotPin;
import io.quarkus.test.junit5.virtual.VirtualThreadUnit;

@VirtualThreadUnit
@ShouldNotPin // You can use @ShouldNotPin or @ShouldPin on the super class itself, it's applied to each method.
public abstract class LoomUnitExampleShouldNotPinOnSuperClass {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit5.virtual.ShouldPin;
import io.quarkus.test.junit5.virtual.internal.TestPinJfrEvent;

public class LoomUnitExampleShouldNotPinOnSuperClassTest extends LoomUnitExampleShouldNotPinOnSuperClass {

@Test
public void failWhenShouldNotPinAndPinDetected() {
TestPinJfrEvent.pin();
}

@Test
@ShouldPin(atMost = 1)
public void overrideClassAnnotation() {
TestPinJfrEvent.pin();
}

@Test
@ShouldPin // Method annotation overrides the class annotation
public void failWhenShouldPinAndNoPinDetected() {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import io.quarkus.test.junit5.virtual.ShouldPin;
import io.quarkus.test.junit5.virtual.VirtualThreadUnit;

@VirtualThreadUnit
@ShouldPin // You can use @ShouldNotPin or @ShouldPin on the super class itself, it's applied to each method.
public abstract class LoomUnitExampleShouldPinOnSuperClass {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.test.junit5.virtual.internal.ignore;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit5.virtual.ShouldNotPin;
import io.quarkus.test.junit5.virtual.internal.TestPinJfrEvent;

public class LoomUnitExampleShouldPinOnSuperClassTest extends LoomUnitExampleShouldPinOnSuperClass {

@Test
@ShouldNotPin // Method annotation overrides the class annotation
public void failWhenShouldNotPinAndPinDetected() {
TestPinJfrEvent.pin();
}

@Test
public void failWhenShouldPinAndNoPinDetected() {

}

}

0 comments on commit f723171

Please sign in to comment.