diff options
author | 2024-01-25 15:00:04 -0700 | |
---|---|---|
committer | 2024-01-26 10:06:18 -0700 | |
commit | 1a84549be3841f3ad9844067b8cc590e0a68efad (patch) | |
tree | f65e390edd2de64bcfd15adbc7923559bcd51761 /ravenwood/junit-src | |
parent | eb64902270ec6805ad82122ff4b2ff19f2b21cec (diff) |
Offer `RavenwoodClassRule`.
Some tests interact with yet-unsupported APIs under Ravenwood in
their test class constructors, and `RavenwoodRule` arrives too late
to effectively apply annotations like `@IgnoreUnderRavenwood`.
This change adds `RavenwoodClassRule` which can be marked as an
`@ClassRule` so that it runs in a static context before each test
class is constructed, giving it a chance to respect annotations.
We also adjust our annotation naming to match the naming style in
JUnit Jupiter, which has annotations like `DisabledOnJre` and
`EnabledOnOs`.
Bug: 319647875
Test: atest SystemUiRoboTests
Test: atest SystemUiRavenTests
Change-Id: I7d834b8e74e961bb3d4befcad6204d99f8fe80e9
Diffstat (limited to 'ravenwood/junit-src')
-rw-r--r-- | ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java (renamed from ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java) | 13 | ||||
-rw-r--r-- | ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java (renamed from ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java) | 13 | ||||
-rw-r--r-- | ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java | 63 | ||||
-rw-r--r-- | ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java | 98 |
4 files changed, 134 insertions, 53 deletions
diff --git a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java index 2ef381e8682c..4bf09807c360 100644 --- a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java +++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java @@ -23,15 +23,16 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Tests marked with this annotation are excluded when running under a Ravenwood test environment. + * Tests marked with this annotation are disabled when running under a Ravenwood test environment. * * A more specific method-level annotation always takes precedence over any class-level - * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over - * an {@link ExcludeUnderRavenwood} annotation. + * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over + * an {@link DisabledOnRavenwood} annotation. * * This annotation only takes effect when the containing class has a {@code - * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit - * .AssumptionViolatedException} which test infrastructure treats as being ignored. + * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by + * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as + * being ignored. * * This annotation has no effect on any other non-Ravenwood test environments. * @@ -40,5 +41,5 @@ import java.lang.annotation.Target; @Inherited @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) -public @interface ExcludeUnderRavenwood { +public @interface DisabledOnRavenwood { } diff --git a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java index 0b2e32f67960..9dd0a58a9db1 100644 --- a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java +++ b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java @@ -23,15 +23,16 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Tests marked with this annotation are included when running under a Ravenwood test environment. + * Tests marked with this annotation are enabled when running under a Ravenwood test environment. * * A more specific method-level annotation always takes precedence over any class-level - * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over - * an {@link ExcludeUnderRavenwood} annotation. + * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over + * an {@link DisabledOnRavenwood} annotation. * * This annotation only takes effect when the containing class has a {@code - * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit - * .AssumptionViolatedException} which test infrastructure treats as being ignored. + * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by + * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as + * being ignored. * * This annotation has no effect on any other non-Ravenwood test environments. * @@ -40,5 +41,5 @@ import java.lang.annotation.Target; @Inherited @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) -public @interface IncludeUnderRavenwood { +public @interface EnabledOnRavenwood { } diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java new file mode 100644 index 000000000000..68b163ede89c --- /dev/null +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.platform.test.ravenwood; + +import static android.platform.test.ravenwood.RavenwoodRule.ENABLE_PROBE_IGNORED; +import static android.platform.test.ravenwood.RavenwoodRule.IS_ON_RAVENWOOD; +import static android.platform.test.ravenwood.RavenwoodRule.shouldEnableOnRavenwood; + +import android.platform.test.annotations.DisabledOnRavenwood; +import android.platform.test.annotations.EnabledOnRavenwood; + +import org.junit.Assume; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * {@code @ClassRule} that respects Ravenwood-specific class annotations. This rule has no effect + * when tests are run on non-Ravenwood test environments. + * + * By default, all tests are executed on Ravenwood, but annotations such as + * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method + * and class level to "ignore" tests that may not be ready. + */ +public class RavenwoodClassRule implements TestRule { + @Override + public Statement apply(Statement base, Description description) { + // No special treatment when running outside Ravenwood; run tests as-is + if (!IS_ON_RAVENWOOD) { + return base; + } + + if (ENABLE_PROBE_IGNORED) { + // Pass through to possible underlying RavenwoodRule for both environment + // configuration and handling method-level annotations + return base; + } else { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Assume.assumeTrue(shouldEnableOnRavenwood(description)); + // Pass through to possible underlying RavenwoodRule for both environment + // configuration and handling method-level annotations + base.evaluate(); + } + }; + } + } +} diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java index dd442f08321f..fef77f9d5ed7 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java @@ -18,9 +18,9 @@ package android.platform.test.ravenwood; import static org.junit.Assert.fail; -import android.platform.test.annotations.ExcludeUnderRavenwood; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.IgnoreUnderRavenwood; -import android.platform.test.annotations.IncludeUnderRavenwood; +import android.platform.test.annotations.EnabledOnRavenwood; import org.junit.Assume; import org.junit.rules.TestRule; @@ -30,29 +30,36 @@ import org.junit.runners.model.Statement; import java.util.concurrent.atomic.AtomicInteger; /** - * THIS RULE IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY - * QUESTIONS ABOUT IT. + * {@code @Rule} that configures the Ravenwood test environment. This rule has no effect when + * tests are run on non-Ravenwood test environments. * - * @hide + * This rule initializes and resets the Ravenwood environment between each test method to offer a + * hermetic testing environment. + * + * By default, all tests are executed on Ravenwood, but annotations such as + * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method + * and class level to "ignore" tests that may not be ready. When needed, a + * {@link RavenwoodClassRule} can be used in addition to a {@link RavenwoodRule} to ignore tests + * before a test class is fully initialized. */ public class RavenwoodRule implements TestRule { - private static AtomicInteger sNextPid = new AtomicInteger(100); - - private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood(); + static final boolean IS_ON_RAVENWOOD = RavenwoodRuleImpl.isOnRavenwood(); /** - * When probing is enabled, all tests will be unconditionally run under Ravenwood to detect + * When probing is enabled, all tests will be unconditionally run on Ravenwood to detect * cases where a test is able to pass despite being marked as {@code IgnoreUnderRavenwood}. * * This is typically helpful for internal maintainers discovering tests that had previously * been ignored, but now have enough Ravenwood-supported functionality to be enabled. */ - private static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE + static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE private static final int SYSTEM_UID = 1000; private static final int NOBODY_UID = 9999; private static final int FIRST_APPLICATION_UID = 10000; + private static final AtomicInteger sNextPid = new AtomicInteger(100); + /** * Unless the test author requests differently, run as "nobody", and give each collection of * tests its own unique PID. @@ -75,7 +82,7 @@ public class RavenwoodRule implements TestRule { /** * Configure the identity of this process to be the system UID for the duration of the - * test. Has no effect under non-Ravenwood environments. + * test. Has no effect on non-Ravenwood environments. */ public Builder setProcessSystem() { mRule.mUid = SYSTEM_UID; @@ -84,7 +91,7 @@ public class RavenwoodRule implements TestRule { /** * Configure the identity of this process to be an app UID for the duration of the - * test. Has no effect under non-Ravenwood environments. + * test. Has no effect on non-Ravenwood environments. */ public Builder setProcessApp() { mRule.mUid = FIRST_APPLICATION_UID; @@ -93,7 +100,7 @@ public class RavenwoodRule implements TestRule { /** * Configure a "main" thread to be available for the duration of the test, as defined - * by {@code Looper.getMainLooper()}. Has no effect under non-Ravenwood environments. + * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments. */ public Builder setProvideMainThread(boolean provideMainThread) { mRule.mProvideMainThread = provideMainThread; @@ -108,7 +115,7 @@ public class RavenwoodRule implements TestRule { * All properties in the {@code debug.*} namespace are automatically mutable, with no * developer action required. * - * Has no effect under non-Ravenwood environments. + * Has no effect on non-Ravenwood environments. */ public Builder setSystemPropertyImmutable(/* @NonNull */ String key, /* @Nullable */ Object value) { @@ -125,7 +132,7 @@ public class RavenwoodRule implements TestRule { * All properties in the {@code debug.*} namespace are automatically mutable, with no * developer action required. * - * Has no effect under non-Ravenwood environments. + * Has no effect on non-Ravenwood environments. */ public Builder setSystemPropertyMutable(/* @NonNull */ String key, /* @Nullable */ Object value) { @@ -140,42 +147,51 @@ public class RavenwoodRule implements TestRule { } /** - * Return if the current process is running under a Ravenwood test environment. + * @deprecated replaced by {@link #isOnRavenwood()} */ + @Deprecated public static boolean isUnderRavenwood() { - return IS_UNDER_RAVENWOOD; + return IS_ON_RAVENWOOD; + } + + /** + * Return if the current process is running on a Ravenwood test environment. + */ + public static boolean isOnRavenwood() { + return IS_ON_RAVENWOOD; } /** - * Determine if the given {@link Description} should be included when running under the + * Determine if the given {@link Description} should be enabled when running on the * Ravenwood test environment. * * A more specific method-level annotation always takes precedence over any class-level - * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over - * an {@link ExcludeUnderRavenwood} annotation. + * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over + * an {@link DisabledOnRavenwood} annotation. */ - private boolean shouldIncludeUnderRavenwood(Description description) { - // Stopgap for http://g/ravenwood/EPAD-N5ntxM - if (description.getMethodName().endsWith("$noRavenwood")) { - return false; - } - + static boolean shouldEnableOnRavenwood(Description description) { // First, consult any method-level annotations - if (description.getAnnotation(IncludeUnderRavenwood.class) != null) { - return true; - } - if (description.getAnnotation(ExcludeUnderRavenwood.class) != null) { - return false; - } - if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) { - return false; + if (description.isTest()) { + // Stopgap for http://g/ravenwood/EPAD-N5ntxM + if (description.getMethodName().endsWith("$noRavenwood")) { + return false; + } + if (description.getAnnotation(EnabledOnRavenwood.class) != null) { + return true; + } + if (description.getAnnotation(DisabledOnRavenwood.class) != null) { + return false; + } + if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) { + return false; + } } // Otherwise, consult any class-level annotations - if (description.getTestClass().getAnnotation(IncludeUnderRavenwood.class) != null) { + if (description.getTestClass().getAnnotation(EnabledOnRavenwood.class) != null) { return true; } - if (description.getTestClass().getAnnotation(ExcludeUnderRavenwood.class) != null) { + if (description.getTestClass().getAnnotation(DisabledOnRavenwood.class) != null) { return false; } if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) { @@ -189,7 +205,7 @@ public class RavenwoodRule implements TestRule { @Override public Statement apply(Statement base, Description description) { // No special treatment when running outside Ravenwood; run tests as-is - if (!IS_UNDER_RAVENWOOD) { + if (!IS_ON_RAVENWOOD) { return base; } @@ -207,7 +223,7 @@ public class RavenwoodRule implements TestRule { return new Statement() { @Override public void evaluate() throws Throwable { - Assume.assumeTrue(shouldIncludeUnderRavenwood(description)); + Assume.assumeTrue(shouldEnableOnRavenwood(description)); RavenwoodRuleImpl.init(RavenwoodRule.this); try { @@ -221,7 +237,7 @@ public class RavenwoodRule implements TestRule { /** * Run the given {@link Statement} with probing enabled. All tests will be unconditionally - * run under Ravenwood to detect cases where a test is able to pass despite being marked as + * run on Ravenwood to detect cases where a test is able to pass despite being marked as * {@code IgnoreUnderRavenwood}. */ private Statement applyProbeIgnored(Statement base, Description description) { @@ -234,13 +250,13 @@ public class RavenwoodRule implements TestRule { } catch (Throwable t) { // If the test isn't included, eat the exception and report the // assumption failure that test authors expect; otherwise throw - Assume.assumeTrue(shouldIncludeUnderRavenwood(description)); + Assume.assumeTrue(shouldEnableOnRavenwood(description)); throw t; } finally { RavenwoodRuleImpl.reset(RavenwoodRule.this); } - if (!shouldIncludeUnderRavenwood(description)) { + if (!shouldEnableOnRavenwood(description)) { fail("Test wasn't included under Ravenwood, but it actually " + "passed under Ravenwood; consider updating annotations"); } |