From 815a921cb2b51e584e036414db3bacbbd6f42841 Mon Sep 17 00:00:00 2001 From: BenWhitehead Date: Tue, 20 Dec 2022 16:58:22 -0500 Subject: [PATCH] test: update StorageITRunner behavior along with @ClassRule Update initialization logic of StorageITRunner to by default disallow use of @ClassRules. Add new annotation @CrossRun.AllowClassRule to allow use of a rule in the event it may be necessary. --- .../cloud/storage/it/runner/StorageITRunner.java | 12 +++++++++--- .../storage/it/runner/annotations/CrossRun.java | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/StorageITRunner.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/StorageITRunner.java index 754ebf9c05..814c5da65c 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/StorageITRunner.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/StorageITRunner.java @@ -18,6 +18,7 @@ import com.google.cloud.storage.it.runner.annotations.Backend; import com.google.cloud.storage.it.runner.annotations.CrossRun; +import com.google.cloud.storage.it.runner.annotations.CrossRun.AllowClassRule; import com.google.cloud.storage.it.runner.annotations.ParallelFriendly; import com.google.cloud.storage.it.runner.annotations.Parameterized; import com.google.cloud.storage.it.runner.annotations.Parameterized.Parameter; @@ -31,6 +32,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.stream.Stream; +import org.junit.ClassRule; import org.junit.runner.Description; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; @@ -136,9 +138,13 @@ private static List computeRunners(Class klass, Registry registry) } if (crossRun != null) { - // TODO - // add warning message if @ClassRule or @BeforeClass/AfterClass are used, as these will run - // multiple times due to the class being run for each crossRun result. + List classRules = testClass.getAnnotatedFields(ClassRule.class); + AllowClassRule allowClassRule = testClass.getAnnotation(AllowClassRule.class); + if (allowClassRule == null && !classRules.isEmpty()) { + String msg = + "@CrossRun used along with @ClassRule. This can be dangerous, multiple class scopes will be created for cross running, possibly breaking expectations on rule scope. If the use of a @ClassRule is still desirable, please annotate your class with @CrossRun.AllowClassRule"; + throw new InitializationError(msg); + } return SneakyException.unwrap( () -> ImmutableSet.copyOf(crossRun.backends()).stream() diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/annotations/CrossRun.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/annotations/CrossRun.java index c5a0d48eb4..960e56e94a 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/annotations/CrossRun.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/annotations/CrossRun.java @@ -70,4 +70,18 @@ TransportCompatibility.Transport[] transports() default {}; } + + /** + * When using {@link CrossRun} a class scope will be created for each permutation, this can break + * expectations of scope/lifecycle for {@link org.junit.ClassRule}s. In an abundance of caution, + * we consider the use of a {@link org.junit.ClassRule} along with {@link CrossRun} an invalid + * class definition. + * + *

In order to allow the use of a {@link org.junit.ClassRule} along with the caveats mentioned + * above, a class can be annotated with {@link AllowClassRule} to suppress the error and proceed + * running the test class with the rule. + */ + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @interface AllowClassRule {} }