Loading ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java +27 −76 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.Suite; Loading Loading @@ -94,7 +93,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase /** Keeps track of the runner on the current thread. */ private static final ThreadLocal<RavenwoodAwareTestRunner> sCurrentRunner = new ThreadLocal<>(); static RavenwoodAwareTestRunner getCurrentRunner() { private static RavenwoodAwareTestRunner getCurrentRunner() { var runner = sCurrentRunner.get(); if (runner == null) { throw new RuntimeException("Current test runner not set!"); Loading @@ -102,11 +101,9 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase return runner; } private final Class<?> mTestJavaClass; final Class<?> mTestJavaClass; private final Runner mRealRunner; private TestClass mTestClass = null; private Runner mRealRunner = null; private Description mDescription = null; private Throwable mExceptionInConstructor = null; /** * Stores internal states / methods associated with this runner that's only needed in Loading @@ -114,17 +111,13 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase */ final RavenwoodRunnerState mState = new RavenwoodRunnerState(this); public TestClass getTestClass() { return mTestClass; } /** * Constructor. */ public RavenwoodAwareTestRunner(Class<?> testClass) { RavenwoodRuntimeEnvironmentController.globalInitOnce(); mTestJavaClass = testClass; try { /* * If the class has @DisabledOnRavenwood, then we'll delegate to * ClassSkippingTestRunner, which simply skips it. Loading @@ -133,7 +126,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase */ if (!RavenwoodEnablementChecker.shouldRunClassOnRavenwood(testClass, true)) { mRealRunner = new ClassSkippingTestRunner(testClass); mDescription = mRealRunner.getDescription(); return; } Loading @@ -141,23 +133,15 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName()); onRunnerInitializing(); // This is needed to make AndroidJUnit4ClassRunner happy. InstrumentationRegistry.registerInstance(null, Bundle.EMPTY); // Hook point to allow more customization. runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null); mRealRunner = instantiateRealRunner(mTestClass); mDescription = mRealRunner.getDescription(); } catch (Throwable th) { // If we throw in the constructor, Tradefed may not report it and just ignore the class, // so record it and throw it when the test actually started. Log.e(TAG, "Fatal: Exception detected in constructor", th); mExceptionInConstructor = new RuntimeException("Exception detected in constructor", th); mDescription = Description.createTestDescription(testClass, "Constructor"); // This is for testing if tradefed is fixed. if ("1".equals(System.getenv("RAVENWOOD_THROW_EXCEPTION_IN_TEST_RUNNER"))) { throw th; } } mState.enterTestRunner(); } @Override Loading @@ -165,23 +149,11 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase return mRealRunner; } /** * Run the bare minimum setup to initialize the wrapped runner. */ // This method is called by the ctor, so never make it virtual. private void onRunnerInitializing() { // This is needed to make AndroidJUnit4ClassRunner happy. InstrumentationRegistry.registerInstance(null, Bundle.EMPTY); // Hook point to allow more customization. runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null); } private void runAnnotatedMethodsOnRavenwood(Class<? extends Annotation> annotationClass, Object instance) { Log.v(TAG, "runAnnotatedMethodsOnRavenwood() " + annotationClass.getName()); for (var method : getTestClass().getAnnotatedMethods(annotationClass)) { for (var method : mTestClass.getAnnotatedMethods(annotationClass)) { ensureIsPublicVoidMethod(method.getMethod(), /* isStatic=*/ instance == null); var methodDesc = method.getDeclaringClass().getName() + "." Loading @@ -194,11 +166,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase } } @Override public Description getDescription() { return mDescription; } @Override public void run(RunNotifier realNotifier) { final var notifier = new RavenwoodRunNotifier(realNotifier); Loading @@ -216,10 +183,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase dumpDescription(description); } if (maybeReportExceptionFromConstructor(notifier)) { return; } // TODO(b/365976974): handle nested classes better final boolean skipRunnerHook = mRealRunnerTakesRunnerBuilder && mRealRunner instanceof Suite; Loading @@ -228,7 +191,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase try { if (!skipRunnerHook) { try { mState.enterTestClass(description); mState.enterTestClass(); } catch (Throwable th) { notifier.reportBeforeTestFailure(description, th); return; Loading @@ -251,18 +214,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase } } /** Throw the exception detected in the constructor, if any. */ private boolean maybeReportExceptionFromConstructor(RunNotifier notifier) { if (mExceptionInConstructor == null) { return false; } notifier.fireTestStarted(mDescription); notifier.fireTestFailure(new Failure(mDescription, mExceptionInConstructor)); notifier.fireTestFinished(mDescription); return true; } private Statement wrapWithHooks(Statement base, Description description, Scope scope, Order order) { return new Statement() { Loading Loading @@ -338,7 +289,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase mState.enterTestMethod(description); } final var classDescription = mState.getClassDescription(); final var classDescription = getDescription(); // Class-level annotations are checked by the runner already, so we only check // method-level annotations here. Loading @@ -360,7 +311,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase private boolean onAfter(Description description, Scope scope, Order order, Throwable th) { Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th); final var classDescription = mState.getClassDescription(); final var classDescription = getDescription(); if (scope == Scope.Instance && order == Order.Outer) { // End of a test method. Loading ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java +57 −44 Original line number Diff line number Diff line Loading @@ -52,37 +52,65 @@ public final class RavenwoodRunnerState { mRunner = runner; } private Description mClassDescription; private Description mMethodDescription; /** * The RavenwoodConfig used to configure the current Ravenwood environment. * This can either come from mConfig or mRule. */ private RavenwoodConfig mCurrentConfig; private RavenwoodRule mCurrentRule; /** * The RavenwoodConfig declared in the test class */ private RavenwoodConfig mConfig; /** * The RavenwoodRule currently in effect, declared in the test class */ private RavenwoodRule mRule; private boolean mHasRavenwoodRule; private Description mMethodDescription; public Description getClassDescription() { return mClassDescription; public RavenwoodConfig getConfig() { return mCurrentConfig; } public void enterTestClass(Description classDescription) { Log.i(TAG, "enterTestClass: description=" + classDescription); mClassDescription = classDescription; public void enterTestRunner() { Log.i(TAG, "enterTestRunner: " + mRunner); mHasRavenwoodRule = hasRavenwoodRule(mRunner.getTestClass().getJavaClass()); mCurrentConfig = extractConfiguration(mRunner.getTestClass().getJavaClass()); mHasRavenwoodRule = hasRavenwoodRule(mRunner.mTestJavaClass); mConfig = extractConfiguration(mRunner.mTestJavaClass); if (mConfig != null) { if (mHasRavenwoodRule) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } mCurrentConfig = mConfig; } else if (!mHasRavenwoodRule) { // If no RavenwoodConfig and no RavenwoodRule, use a default config mCurrentConfig = new RavenwoodConfig.Builder().build(); } if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.init(mCurrentConfig); RavenwoodRuntimeEnvironmentController.init(mRunner); } } public void exitTestClass() { Log.i(TAG, "exitTestClass: description=" + mClassDescription); public void enterTestClass() { Log.i(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName()); if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.init(mRunner); } } public void exitTestClass() { Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName()); try { if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.reset(); } finally { mClassDescription = null; } } finally { mConfig = null; mRule = null; } } Loading @@ -92,6 +120,7 @@ public final class RavenwoodRunnerState { public void exitTestMethod() { mMethodDescription = null; RavenwoodRuntimeEnvironmentController.reinit(); } public void enterRavenwoodRule(RavenwoodRule rule) { Loading @@ -99,50 +128,34 @@ public final class RavenwoodRunnerState { fail("If you have a RavenwoodRule in your test, make sure the field type is" + " RavenwoodRule so Ravenwood can detect it."); } if (mCurrentConfig != null) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } if (mCurrentRule != null) { if (mRule != null) { fail("Multiple nesting RavenwoodRule's are detected in the same class," + " which is not supported."); } mCurrentRule = rule; RavenwoodRuntimeEnvironmentController.init(rule.getConfiguration()); mRule = rule; if (mCurrentConfig == null) { mCurrentConfig = rule.getConfiguration(); } public void exitRavenwoodRule(RavenwoodRule rule) { if (mCurrentRule != rule) { return; // This happens if the rule did _not_ take effect somehow. RavenwoodRuntimeEnvironmentController.init(mRunner); } try { RavenwoodRuntimeEnvironmentController.reset(); } finally { mCurrentRule = null; public void exitRavenwoodRule(RavenwoodRule rule) { if (mRule != rule) { fail("RavenwoodRule did not take effect."); } mRule = null; } /** * @return a configuration from a test class, if any. */ @Nullable private RavenwoodConfig extractConfiguration(Class<?> testClass) { private static RavenwoodConfig extractConfiguration(Class<?> testClass) { var field = findConfigurationField(testClass); if (field == null) { if (mHasRavenwoodRule) { // Should be handled by RavenwoodRule return null; } // If no RavenwoodConfig and no RavenwoodRule, return a default config return new RavenwoodConfig.Builder().build(); } if (mHasRavenwoodRule) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } try { return (RavenwoodConfig) field.get(null); } catch (IllegalAccessException e) { Loading ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +27 −18 Original line number Diff line number Diff line Loading @@ -137,7 +137,7 @@ public class RavenwoodRuntimeEnvironmentController { return res; } private static RavenwoodConfig sConfig; private static RavenwoodAwareTestRunner sRunner; private static RavenwoodSystemProperties sProps; private static boolean sInitialized = false; Loading Loading @@ -171,6 +171,10 @@ public class RavenwoodRuntimeEnvironmentController { // Redirect stdout/stdin to liblog. RuntimeInit.redirectLogStreams(); // Touch some references early to ensure they're <clinit>'ed Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); if (RAVENWOOD_VERBOSE_LOGGING) { RavenwoodCommonUtils.log(TAG, "Force enabling verbose logging"); try { Loading @@ -191,12 +195,19 @@ public class RavenwoodRuntimeEnvironmentController { /** * Initialize the environment. */ public static void init(RavenwoodConfig config) { public static void init(RavenwoodAwareTestRunner runner) { if (RAVENWOOD_VERBOSE_LOGGING) { Log.i(TAG, "init() called here", new RuntimeException("STACKTRACE")); Log.i(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE")); } if (sRunner == runner) { return; } if (sRunner != null) { reset(); } sRunner = runner; try { initInner(config); initInner(runner.mState.getConfig()); } catch (Exception th) { Log.e(TAG, "init() failed", th); reset(); Loading @@ -205,10 +216,6 @@ public class RavenwoodRuntimeEnvironmentController { } private static void initInner(RavenwoodConfig config) throws IOException { if (sConfig != null) { throw new RavenwoodRuntimeException("Internal error: init() called without reset()"); } sConfig = config; if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { maybeThrowPendingUncaughtException(false); Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); Loading @@ -216,7 +223,7 @@ public class RavenwoodRuntimeEnvironmentController { android.os.Process.init$ravenwood(config.mUid, config.mPid); sOriginalIdentityToken = Binder.clearCallingIdentity(); Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid)); reinit(); setSystemProperties(config.mSystemProperties); ServiceManager.init$ravenwood(); Loading Loading @@ -269,9 +276,7 @@ public class RavenwoodRuntimeEnvironmentController { config.mInstContext = instContext; config.mTargetContext = targetContext; final Supplier<Resources> systemResourcesLoader = () -> { return config.mState.loadResources(null); }; final Supplier<Resources> systemResourcesLoader = () -> config.mState.loadResources(null); config.mState.mSystemServerContext = new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader); Loading @@ -288,10 +293,14 @@ public class RavenwoodRuntimeEnvironmentController { RavenwoodRuntimeEnvironmentController::dumpStacks, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } } // Touch some references early to ensure they're <clinit>'ed Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); /** * Partially re-initialize after each test method invocation */ public static void reinit() { var config = sRunner.mState.getConfig(); Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid)); } /** Loading @@ -301,11 +310,11 @@ public class RavenwoodRuntimeEnvironmentController { if (RAVENWOOD_VERBOSE_LOGGING) { Log.i(TAG, "reset() called here", new RuntimeException("STACKTRACE")); } if (sConfig == null) { if (sRunner == null) { throw new RavenwoodRuntimeException("Internal error: reset() already called"); } var config = sConfig; sConfig = null; var config = sRunner.mState.getConfig(); sRunner = null; if (ENABLE_TIMEOUT_STACKS) { sPendingTimeout.cancel(false); Loading ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ abstract class RavenwoodAwareTestRunnerBase extends Runner implements Filterable } @Override public Description getDescription() { public final Description getDescription() { return getRealRunner().getDescription(); } Loading ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +4 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.app.Instrumentation; import android.content.Context; import android.platform.test.annotations.DisabledOnRavenwood; import androidx.test.platform.app.InstrumentationRegistry; import com.android.ravenwood.common.RavenwoodCommonUtils; import org.junit.rules.TestRule; Loading Loading @@ -219,8 +221,7 @@ public final class RavenwoodRule implements TestRule { */ @Deprecated public Context getContext() { return Objects.requireNonNull(mConfiguration.mInstContext, "Context is only available during @Test execution"); return InstrumentationRegistry.getInstrumentation().getContext(); } /** Loading @@ -230,8 +231,7 @@ public final class RavenwoodRule implements TestRule { */ @Deprecated public Instrumentation getInstrumentation() { return Objects.requireNonNull(mConfiguration.mInstrumentation, "Instrumentation is only available during @Test execution"); return InstrumentationRegistry.getInstrumentation(); } @Override Loading Loading
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java +27 −76 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.Suite; Loading Loading @@ -94,7 +93,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase /** Keeps track of the runner on the current thread. */ private static final ThreadLocal<RavenwoodAwareTestRunner> sCurrentRunner = new ThreadLocal<>(); static RavenwoodAwareTestRunner getCurrentRunner() { private static RavenwoodAwareTestRunner getCurrentRunner() { var runner = sCurrentRunner.get(); if (runner == null) { throw new RuntimeException("Current test runner not set!"); Loading @@ -102,11 +101,9 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase return runner; } private final Class<?> mTestJavaClass; final Class<?> mTestJavaClass; private final Runner mRealRunner; private TestClass mTestClass = null; private Runner mRealRunner = null; private Description mDescription = null; private Throwable mExceptionInConstructor = null; /** * Stores internal states / methods associated with this runner that's only needed in Loading @@ -114,17 +111,13 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase */ final RavenwoodRunnerState mState = new RavenwoodRunnerState(this); public TestClass getTestClass() { return mTestClass; } /** * Constructor. */ public RavenwoodAwareTestRunner(Class<?> testClass) { RavenwoodRuntimeEnvironmentController.globalInitOnce(); mTestJavaClass = testClass; try { /* * If the class has @DisabledOnRavenwood, then we'll delegate to * ClassSkippingTestRunner, which simply skips it. Loading @@ -133,7 +126,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase */ if (!RavenwoodEnablementChecker.shouldRunClassOnRavenwood(testClass, true)) { mRealRunner = new ClassSkippingTestRunner(testClass); mDescription = mRealRunner.getDescription(); return; } Loading @@ -141,23 +133,15 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName()); onRunnerInitializing(); // This is needed to make AndroidJUnit4ClassRunner happy. InstrumentationRegistry.registerInstance(null, Bundle.EMPTY); // Hook point to allow more customization. runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null); mRealRunner = instantiateRealRunner(mTestClass); mDescription = mRealRunner.getDescription(); } catch (Throwable th) { // If we throw in the constructor, Tradefed may not report it and just ignore the class, // so record it and throw it when the test actually started. Log.e(TAG, "Fatal: Exception detected in constructor", th); mExceptionInConstructor = new RuntimeException("Exception detected in constructor", th); mDescription = Description.createTestDescription(testClass, "Constructor"); // This is for testing if tradefed is fixed. if ("1".equals(System.getenv("RAVENWOOD_THROW_EXCEPTION_IN_TEST_RUNNER"))) { throw th; } } mState.enterTestRunner(); } @Override Loading @@ -165,23 +149,11 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase return mRealRunner; } /** * Run the bare minimum setup to initialize the wrapped runner. */ // This method is called by the ctor, so never make it virtual. private void onRunnerInitializing() { // This is needed to make AndroidJUnit4ClassRunner happy. InstrumentationRegistry.registerInstance(null, Bundle.EMPTY); // Hook point to allow more customization. runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null); } private void runAnnotatedMethodsOnRavenwood(Class<? extends Annotation> annotationClass, Object instance) { Log.v(TAG, "runAnnotatedMethodsOnRavenwood() " + annotationClass.getName()); for (var method : getTestClass().getAnnotatedMethods(annotationClass)) { for (var method : mTestClass.getAnnotatedMethods(annotationClass)) { ensureIsPublicVoidMethod(method.getMethod(), /* isStatic=*/ instance == null); var methodDesc = method.getDeclaringClass().getName() + "." Loading @@ -194,11 +166,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase } } @Override public Description getDescription() { return mDescription; } @Override public void run(RunNotifier realNotifier) { final var notifier = new RavenwoodRunNotifier(realNotifier); Loading @@ -216,10 +183,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase dumpDescription(description); } if (maybeReportExceptionFromConstructor(notifier)) { return; } // TODO(b/365976974): handle nested classes better final boolean skipRunnerHook = mRealRunnerTakesRunnerBuilder && mRealRunner instanceof Suite; Loading @@ -228,7 +191,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase try { if (!skipRunnerHook) { try { mState.enterTestClass(description); mState.enterTestClass(); } catch (Throwable th) { notifier.reportBeforeTestFailure(description, th); return; Loading @@ -251,18 +214,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase } } /** Throw the exception detected in the constructor, if any. */ private boolean maybeReportExceptionFromConstructor(RunNotifier notifier) { if (mExceptionInConstructor == null) { return false; } notifier.fireTestStarted(mDescription); notifier.fireTestFailure(new Failure(mDescription, mExceptionInConstructor)); notifier.fireTestFinished(mDescription); return true; } private Statement wrapWithHooks(Statement base, Description description, Scope scope, Order order) { return new Statement() { Loading Loading @@ -338,7 +289,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase mState.enterTestMethod(description); } final var classDescription = mState.getClassDescription(); final var classDescription = getDescription(); // Class-level annotations are checked by the runner already, so we only check // method-level annotations here. Loading @@ -360,7 +311,7 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase private boolean onAfter(Description description, Scope scope, Order order, Throwable th) { Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th); final var classDescription = mState.getClassDescription(); final var classDescription = getDescription(); if (scope == Scope.Instance && order == Order.Outer) { // End of a test method. Loading
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java +57 −44 Original line number Diff line number Diff line Loading @@ -52,37 +52,65 @@ public final class RavenwoodRunnerState { mRunner = runner; } private Description mClassDescription; private Description mMethodDescription; /** * The RavenwoodConfig used to configure the current Ravenwood environment. * This can either come from mConfig or mRule. */ private RavenwoodConfig mCurrentConfig; private RavenwoodRule mCurrentRule; /** * The RavenwoodConfig declared in the test class */ private RavenwoodConfig mConfig; /** * The RavenwoodRule currently in effect, declared in the test class */ private RavenwoodRule mRule; private boolean mHasRavenwoodRule; private Description mMethodDescription; public Description getClassDescription() { return mClassDescription; public RavenwoodConfig getConfig() { return mCurrentConfig; } public void enterTestClass(Description classDescription) { Log.i(TAG, "enterTestClass: description=" + classDescription); mClassDescription = classDescription; public void enterTestRunner() { Log.i(TAG, "enterTestRunner: " + mRunner); mHasRavenwoodRule = hasRavenwoodRule(mRunner.getTestClass().getJavaClass()); mCurrentConfig = extractConfiguration(mRunner.getTestClass().getJavaClass()); mHasRavenwoodRule = hasRavenwoodRule(mRunner.mTestJavaClass); mConfig = extractConfiguration(mRunner.mTestJavaClass); if (mConfig != null) { if (mHasRavenwoodRule) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } mCurrentConfig = mConfig; } else if (!mHasRavenwoodRule) { // If no RavenwoodConfig and no RavenwoodRule, use a default config mCurrentConfig = new RavenwoodConfig.Builder().build(); } if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.init(mCurrentConfig); RavenwoodRuntimeEnvironmentController.init(mRunner); } } public void exitTestClass() { Log.i(TAG, "exitTestClass: description=" + mClassDescription); public void enterTestClass() { Log.i(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName()); if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.init(mRunner); } } public void exitTestClass() { Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName()); try { if (mCurrentConfig != null) { RavenwoodRuntimeEnvironmentController.reset(); } finally { mClassDescription = null; } } finally { mConfig = null; mRule = null; } } Loading @@ -92,6 +120,7 @@ public final class RavenwoodRunnerState { public void exitTestMethod() { mMethodDescription = null; RavenwoodRuntimeEnvironmentController.reinit(); } public void enterRavenwoodRule(RavenwoodRule rule) { Loading @@ -99,50 +128,34 @@ public final class RavenwoodRunnerState { fail("If you have a RavenwoodRule in your test, make sure the field type is" + " RavenwoodRule so Ravenwood can detect it."); } if (mCurrentConfig != null) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } if (mCurrentRule != null) { if (mRule != null) { fail("Multiple nesting RavenwoodRule's are detected in the same class," + " which is not supported."); } mCurrentRule = rule; RavenwoodRuntimeEnvironmentController.init(rule.getConfiguration()); mRule = rule; if (mCurrentConfig == null) { mCurrentConfig = rule.getConfiguration(); } public void exitRavenwoodRule(RavenwoodRule rule) { if (mCurrentRule != rule) { return; // This happens if the rule did _not_ take effect somehow. RavenwoodRuntimeEnvironmentController.init(mRunner); } try { RavenwoodRuntimeEnvironmentController.reset(); } finally { mCurrentRule = null; public void exitRavenwoodRule(RavenwoodRule rule) { if (mRule != rule) { fail("RavenwoodRule did not take effect."); } mRule = null; } /** * @return a configuration from a test class, if any. */ @Nullable private RavenwoodConfig extractConfiguration(Class<?> testClass) { private static RavenwoodConfig extractConfiguration(Class<?> testClass) { var field = findConfigurationField(testClass); if (field == null) { if (mHasRavenwoodRule) { // Should be handled by RavenwoodRule return null; } // If no RavenwoodConfig and no RavenwoodRule, return a default config return new RavenwoodConfig.Builder().build(); } if (mHasRavenwoodRule) { fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class." + " Suggest migrating to RavenwoodConfig."); } try { return (RavenwoodConfig) field.get(null); } catch (IllegalAccessException e) { Loading
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +27 −18 Original line number Diff line number Diff line Loading @@ -137,7 +137,7 @@ public class RavenwoodRuntimeEnvironmentController { return res; } private static RavenwoodConfig sConfig; private static RavenwoodAwareTestRunner sRunner; private static RavenwoodSystemProperties sProps; private static boolean sInitialized = false; Loading Loading @@ -171,6 +171,10 @@ public class RavenwoodRuntimeEnvironmentController { // Redirect stdout/stdin to liblog. RuntimeInit.redirectLogStreams(); // Touch some references early to ensure they're <clinit>'ed Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); if (RAVENWOOD_VERBOSE_LOGGING) { RavenwoodCommonUtils.log(TAG, "Force enabling verbose logging"); try { Loading @@ -191,12 +195,19 @@ public class RavenwoodRuntimeEnvironmentController { /** * Initialize the environment. */ public static void init(RavenwoodConfig config) { public static void init(RavenwoodAwareTestRunner runner) { if (RAVENWOOD_VERBOSE_LOGGING) { Log.i(TAG, "init() called here", new RuntimeException("STACKTRACE")); Log.i(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE")); } if (sRunner == runner) { return; } if (sRunner != null) { reset(); } sRunner = runner; try { initInner(config); initInner(runner.mState.getConfig()); } catch (Exception th) { Log.e(TAG, "init() failed", th); reset(); Loading @@ -205,10 +216,6 @@ public class RavenwoodRuntimeEnvironmentController { } private static void initInner(RavenwoodConfig config) throws IOException { if (sConfig != null) { throw new RavenwoodRuntimeException("Internal error: init() called without reset()"); } sConfig = config; if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { maybeThrowPendingUncaughtException(false); Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); Loading @@ -216,7 +223,7 @@ public class RavenwoodRuntimeEnvironmentController { android.os.Process.init$ravenwood(config.mUid, config.mPid); sOriginalIdentityToken = Binder.clearCallingIdentity(); Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid)); reinit(); setSystemProperties(config.mSystemProperties); ServiceManager.init$ravenwood(); Loading Loading @@ -269,9 +276,7 @@ public class RavenwoodRuntimeEnvironmentController { config.mInstContext = instContext; config.mTargetContext = targetContext; final Supplier<Resources> systemResourcesLoader = () -> { return config.mState.loadResources(null); }; final Supplier<Resources> systemResourcesLoader = () -> config.mState.loadResources(null); config.mState.mSystemServerContext = new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader); Loading @@ -288,10 +293,14 @@ public class RavenwoodRuntimeEnvironmentController { RavenwoodRuntimeEnvironmentController::dumpStacks, TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } } // Touch some references early to ensure they're <clinit>'ed Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); /** * Partially re-initialize after each test method invocation */ public static void reinit() { var config = sRunner.mState.getConfig(); Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid)); } /** Loading @@ -301,11 +310,11 @@ public class RavenwoodRuntimeEnvironmentController { if (RAVENWOOD_VERBOSE_LOGGING) { Log.i(TAG, "reset() called here", new RuntimeException("STACKTRACE")); } if (sConfig == null) { if (sRunner == null) { throw new RavenwoodRuntimeException("Internal error: reset() already called"); } var config = sConfig; sConfig = null; var config = sRunner.mState.getConfig(); sRunner = null; if (ENABLE_TIMEOUT_STACKS) { sPendingTimeout.cancel(false); Loading
ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ abstract class RavenwoodAwareTestRunnerBase extends Runner implements Filterable } @Override public Description getDescription() { public final Description getDescription() { return getRealRunner().getDescription(); } Loading
ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +4 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.app.Instrumentation; import android.content.Context; import android.platform.test.annotations.DisabledOnRavenwood; import androidx.test.platform.app.InstrumentationRegistry; import com.android.ravenwood.common.RavenwoodCommonUtils; import org.junit.rules.TestRule; Loading Loading @@ -219,8 +221,7 @@ public final class RavenwoodRule implements TestRule { */ @Deprecated public Context getContext() { return Objects.requireNonNull(mConfiguration.mInstContext, "Context is only available during @Test execution"); return InstrumentationRegistry.getInstrumentation().getContext(); } /** Loading @@ -230,8 +231,7 @@ public final class RavenwoodRule implements TestRule { */ @Deprecated public Instrumentation getInstrumentation() { return Objects.requireNonNull(mConfiguration.mInstrumentation, "Instrumentation is only available during @Test execution"); return InstrumentationRegistry.getInstrumentation(); } @Override Loading