Loading ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +20 −12 Original line number Diff line number Diff line Loading @@ -131,11 +131,13 @@ public class RavenwoodRuntimeEnvironmentController { private static final boolean ENABLE_TIMEOUT_STACKS = !"0".equals(System.getenv("RAVENWOOD_ENABLE_TIMEOUT_STACKS")); private static final boolean TOLERATE_LOOPER_ASSERTS = !"0".equals(System.getenv("RAVENWOOD_TOLERATE_LOOPER_ASSERTS")); /** RavenwoodCoreTest modifies it, so not final. */ public static volatile boolean TOLERATE_UNHANDLED_ASSERTS = !"0".equals(System.getenv("RAVENWOOD_TOLERATE_UNHANDLED_ASSERTS")); private static final boolean TOLERATE_LOOPER_EXCEPTIONS = "1".equals(System.getenv("RAVENWOOD_TOLERATE_LOOPER_EXCEPTIONS")); /** RavenwoodCoreTest modifies it, so not final. */ public static volatile boolean TOLERATE_UNHANDLED_EXCEPTIONS = "1".equals(System.getenv("RAVENWOOD_TOLERATE_UNHANDLED_EXCEPTIONS")); static final int DEFAULT_TIMEOUT_SECONDS = 10; private static final int TIMEOUT_MILLIS = getTimeoutSeconds() * 1000; Loading Loading @@ -596,16 +598,22 @@ public class RavenwoodRuntimeEnvironmentController { } /** * Return if an exception is benign and okay to continue running the main looper even * if we detect it. * Return if an exception is benign and okay to continue running the remaining tests. */ private static boolean isThrowableRecoverable(Throwable th) { return th instanceof AssertionError || th instanceof AssumptionViolatedException; if (TOLERATE_UNHANDLED_EXCEPTIONS) { return true; } if (TOLERATE_UNHANDLED_ASSERTS && (th instanceof AssertionError || th instanceof AssumptionViolatedException)) { return true; } return false; } private static Exception makeRecoverableExceptionInstance(Throwable inner) { var outer = new Exception(String.format("Exception detected on thread %s: " + " *** Continuing the test because it's recoverable ***", + " *** Continuing running the remaining tests ***", Thread.currentThread().getName()), inner); Log.e(TAG, outer.getMessage(), outer); return outer; Loading @@ -618,8 +626,7 @@ public class RavenwoodRuntimeEnvironmentController { var desc = String.format("Detected %s on looper thread %s", th.getClass().getName(), Thread.currentThread()); sStdErr.println(desc); if (TOLERATE_LOOPER_EXCEPTIONS || (TOLERATE_LOOPER_ASSERTS && isThrowableRecoverable(th))) { if (isThrowableRecoverable(th)) { sPendingRecoverableUncaughtException.compareAndSet(null, makeRecoverableExceptionInstance(th)); return; Loading Loading @@ -767,7 +774,6 @@ public class RavenwoodRuntimeEnvironmentController { } private static void onUncaughtException(Thread thread, Throwable inner) { if (isThrowableRecoverable(inner)) { sPendingRecoverableUncaughtException.compareAndSet(null, makeRecoverableExceptionInstance(inner)); Loading @@ -775,7 +781,9 @@ public class RavenwoodRuntimeEnvironmentController { } var msg = String.format( "Uncaught exception detected on thread %s, test=%s:" + " %s; Failing all subsequent tests", + " %s; Failing all subsequent tests." + " (Run with `RAVENWOOD_TOLERATE_UNHANDLED_EXCEPTIONS=1 atest...` to " + "force run the subsequent tests)", thread, sCurrentDescription, RavenwoodCommonUtils.getStackTraceString(inner)); var outer = new Exception(msg, inner); Loading ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java +2 −3 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package android.platform.test.ravenwood; import static com.android.ravenwood.common.RavenwoodCommonUtils.ReflectedMethod.reflectMethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; Loading @@ -27,6 +25,7 @@ import com.android.ravenwood.common.SneakyThrow; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; Loading Loading @@ -89,7 +88,7 @@ public class RavenwoodUtils { latch.countDown(); }); try { latch.await(); latch.await(30, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException("Interrupted while waiting on the Runnable", e); } Loading ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java +0 −39 Original line number Diff line number Diff line Loading @@ -15,20 +15,13 @@ */ package com.android.ravenwoodtest.runnercallbacktests; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import android.os.Handler; import android.os.Looper; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.NoRavenizer; import android.platform.test.ravenwood.RavenwoodAwareTestRunner; import android.platform.test.ravenwood.RavenwoodUtils; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.AfterClass; import org.junit.Assert; Loading @@ -45,7 +38,6 @@ import org.junit.runners.model.Statement; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; Loading Loading @@ -463,35 +455,4 @@ public class RavenwoodRunnerCallbackTest extends RavenwoodRunnerTestBase { public void test2() { } } /** */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing the test because it's recoverable *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadAssertionFailureTest { @Test public void test1() { var h = new Handler(Looper.getMainLooper()); h.post(() -> fail("If testMainThreadAssertionFailure() fails with this, that's expected.")); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // The looper should still be alive, so this should work. (if the looper has finished, // this would hang.) var value = new AtomicInteger(0); RavenwoodUtils.runOnMainThreadSync(() -> value.set(1) ); assertThat(value.get()).isEqualTo(1); } } } ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerExecutionTest.java 0 → 100644 +164 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 com.android.ravenwoodtest.runnercallbacktests; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import android.os.Handler; import android.os.Looper; import android.platform.test.annotations.NoRavenizer; import android.platform.test.ravenwood.RavenwoodRuntimeEnvironmentController; import android.platform.test.ravenwood.RavenwoodUtils; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import java.util.concurrent.atomic.AtomicInteger; @NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner. public class RavenwoodRunnerExecutionTest extends RavenwoodRunnerTestBase { private static boolean sOrigTolerateUnhandledAsserts; private static boolean sOrigTolerateUnhandledExceptions; /** Save the TOLERATE_* flags and set them to false. */ private static void initTolerateFlags() { sOrigTolerateUnhandledAsserts = RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS; sOrigTolerateUnhandledExceptions = RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = false; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = false; } /** Restore the original TOLERATE_* flags. */ private static void restoreTolerateFlags() { RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = sOrigTolerateUnhandledAsserts; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = sOrigTolerateUnhandledExceptions; } private static void ensureMainThreadAlive() { var value = new AtomicInteger(0); RavenwoodUtils.runOnMainThreadSync(() -> value.set(1)); assertThat(value.get()).isEqualTo(1); } /** * Make sure TOLERATE_UNHANDLED_ASSERTS works. */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing running the remaining tests *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadAssertionFailureTest { @BeforeClass public static void beforeClass() { initTolerateFlags(); // Comment it out to test the false case. RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = true; } @AfterClass public static void afterClass() { restoreTolerateFlags(); } @Test public void test1() throws Exception { var h = new Handler(Looper.getMainLooper()); h.post(() -> fail("failed on the man thread")); // If the flag isn't set to true, then the looper would be dead, so don't do it. if (RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS) { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); ensureMainThreadAlive(); } else { // waitForIdleSync() won't work, so just wait for a bit... Thread.sleep(5_000); } } } /** * Make sure TOLERATE_UNHANDLED_EXCEPTIONS works. */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing running the remaining tests *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadRuntimeExceptionTest { @BeforeClass public static void beforeClass() { initTolerateFlags(); // Comment it out to test the false case. RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = true; } @AfterClass public static void afterClass() { restoreTolerateFlags(); } @Test public void test1() throws Exception { var h = new Handler(Looper.getMainLooper()); h.post(() -> { throw new RuntimeException("exception on the man thread"); }); // If the flag isn't set to true, then the looper would be dead, so don't do it. if (RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS) { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); ensureMainThreadAlive(); } else { // waitForIdleSync() won't work, so just wait for a bit... Thread.sleep(5_000); } } } } Loading
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +20 −12 Original line number Diff line number Diff line Loading @@ -131,11 +131,13 @@ public class RavenwoodRuntimeEnvironmentController { private static final boolean ENABLE_TIMEOUT_STACKS = !"0".equals(System.getenv("RAVENWOOD_ENABLE_TIMEOUT_STACKS")); private static final boolean TOLERATE_LOOPER_ASSERTS = !"0".equals(System.getenv("RAVENWOOD_TOLERATE_LOOPER_ASSERTS")); /** RavenwoodCoreTest modifies it, so not final. */ public static volatile boolean TOLERATE_UNHANDLED_ASSERTS = !"0".equals(System.getenv("RAVENWOOD_TOLERATE_UNHANDLED_ASSERTS")); private static final boolean TOLERATE_LOOPER_EXCEPTIONS = "1".equals(System.getenv("RAVENWOOD_TOLERATE_LOOPER_EXCEPTIONS")); /** RavenwoodCoreTest modifies it, so not final. */ public static volatile boolean TOLERATE_UNHANDLED_EXCEPTIONS = "1".equals(System.getenv("RAVENWOOD_TOLERATE_UNHANDLED_EXCEPTIONS")); static final int DEFAULT_TIMEOUT_SECONDS = 10; private static final int TIMEOUT_MILLIS = getTimeoutSeconds() * 1000; Loading Loading @@ -596,16 +598,22 @@ public class RavenwoodRuntimeEnvironmentController { } /** * Return if an exception is benign and okay to continue running the main looper even * if we detect it. * Return if an exception is benign and okay to continue running the remaining tests. */ private static boolean isThrowableRecoverable(Throwable th) { return th instanceof AssertionError || th instanceof AssumptionViolatedException; if (TOLERATE_UNHANDLED_EXCEPTIONS) { return true; } if (TOLERATE_UNHANDLED_ASSERTS && (th instanceof AssertionError || th instanceof AssumptionViolatedException)) { return true; } return false; } private static Exception makeRecoverableExceptionInstance(Throwable inner) { var outer = new Exception(String.format("Exception detected on thread %s: " + " *** Continuing the test because it's recoverable ***", + " *** Continuing running the remaining tests ***", Thread.currentThread().getName()), inner); Log.e(TAG, outer.getMessage(), outer); return outer; Loading @@ -618,8 +626,7 @@ public class RavenwoodRuntimeEnvironmentController { var desc = String.format("Detected %s on looper thread %s", th.getClass().getName(), Thread.currentThread()); sStdErr.println(desc); if (TOLERATE_LOOPER_EXCEPTIONS || (TOLERATE_LOOPER_ASSERTS && isThrowableRecoverable(th))) { if (isThrowableRecoverable(th)) { sPendingRecoverableUncaughtException.compareAndSet(null, makeRecoverableExceptionInstance(th)); return; Loading Loading @@ -767,7 +774,6 @@ public class RavenwoodRuntimeEnvironmentController { } private static void onUncaughtException(Thread thread, Throwable inner) { if (isThrowableRecoverable(inner)) { sPendingRecoverableUncaughtException.compareAndSet(null, makeRecoverableExceptionInstance(inner)); Loading @@ -775,7 +781,9 @@ public class RavenwoodRuntimeEnvironmentController { } var msg = String.format( "Uncaught exception detected on thread %s, test=%s:" + " %s; Failing all subsequent tests", + " %s; Failing all subsequent tests." + " (Run with `RAVENWOOD_TOLERATE_UNHANDLED_EXCEPTIONS=1 atest...` to " + "force run the subsequent tests)", thread, sCurrentDescription, RavenwoodCommonUtils.getStackTraceString(inner)); var outer = new Exception(msg, inner); Loading
ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java +2 −3 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package android.platform.test.ravenwood; import static com.android.ravenwood.common.RavenwoodCommonUtils.ReflectedMethod.reflectMethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; Loading @@ -27,6 +25,7 @@ import com.android.ravenwood.common.SneakyThrow; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; Loading Loading @@ -89,7 +88,7 @@ public class RavenwoodUtils { latch.countDown(); }); try { latch.await(); latch.await(30, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException("Interrupted while waiting on the Runnable", e); } Loading
ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java +0 −39 Original line number Diff line number Diff line Loading @@ -15,20 +15,13 @@ */ package com.android.ravenwoodtest.runnercallbacktests; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import android.os.Handler; import android.os.Looper; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.NoRavenizer; import android.platform.test.ravenwood.RavenwoodAwareTestRunner; import android.platform.test.ravenwood.RavenwoodUtils; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.AfterClass; import org.junit.Assert; Loading @@ -45,7 +38,6 @@ import org.junit.runners.model.Statement; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; Loading Loading @@ -463,35 +455,4 @@ public class RavenwoodRunnerCallbackTest extends RavenwoodRunnerTestBase { public void test2() { } } /** */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing the test because it's recoverable *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$MainThreadAssertionFailureTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadAssertionFailureTest { @Test public void test1() { var h = new Handler(Looper.getMainLooper()); h.post(() -> fail("If testMainThreadAssertionFailure() fails with this, that's expected.")); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // The looper should still be alive, so this should work. (if the looper has finished, // this would hang.) var value = new AtomicInteger(0); RavenwoodUtils.runOnMainThreadSync(() -> value.set(1) ); assertThat(value.get()).isEqualTo(1); } } }
ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerExecutionTest.java 0 → 100644 +164 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 com.android.ravenwoodtest.runnercallbacktests; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import android.os.Handler; import android.os.Looper; import android.platform.test.annotations.NoRavenizer; import android.platform.test.ravenwood.RavenwoodRuntimeEnvironmentController; import android.platform.test.ravenwood.RavenwoodUtils; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import java.util.concurrent.atomic.AtomicInteger; @NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner. public class RavenwoodRunnerExecutionTest extends RavenwoodRunnerTestBase { private static boolean sOrigTolerateUnhandledAsserts; private static boolean sOrigTolerateUnhandledExceptions; /** Save the TOLERATE_* flags and set them to false. */ private static void initTolerateFlags() { sOrigTolerateUnhandledAsserts = RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS; sOrigTolerateUnhandledExceptions = RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = false; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = false; } /** Restore the original TOLERATE_* flags. */ private static void restoreTolerateFlags() { RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = sOrigTolerateUnhandledAsserts; RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = sOrigTolerateUnhandledExceptions; } private static void ensureMainThreadAlive() { var value = new AtomicInteger(0); RavenwoodUtils.runOnMainThreadSync(() -> value.set(1)); assertThat(value.get()).isEqualTo(1); } /** * Make sure TOLERATE_UNHANDLED_ASSERTS works. */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing running the remaining tests *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadAssertionFailureTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadAssertionFailureTest { @BeforeClass public static void beforeClass() { initTolerateFlags(); // Comment it out to test the false case. RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS = true; } @AfterClass public static void afterClass() { restoreTolerateFlags(); } @Test public void test1() throws Exception { var h = new Handler(Looper.getMainLooper()); h.post(() -> fail("failed on the man thread")); // If the flag isn't set to true, then the looper would be dead, so don't do it. if (RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_ASSERTS) { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); ensureMainThreadAlive(); } else { // waitForIdleSync() won't work, so just wait for a bit... Thread.sleep(5_000); } } } /** * Make sure TOLERATE_UNHANDLED_EXCEPTIONS works. */ @RunWith(AndroidJUnit4.class) // CHECKSTYLE:OFF @Expected(""" testRunStarted: classes testSuiteStarted: classes testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest) testFailure: Exception detected on thread Ravenwood:Main: *** Continuing running the remaining tests *** testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest) testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerExecutionTest$MainThreadRuntimeExceptionTest testSuiteFinished: classes testRunFinished: 1,1,0,0 """) // CHECKSTYLE:ON public static class MainThreadRuntimeExceptionTest { @BeforeClass public static void beforeClass() { initTolerateFlags(); // Comment it out to test the false case. RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS = true; } @AfterClass public static void afterClass() { restoreTolerateFlags(); } @Test public void test1() throws Exception { var h = new Handler(Looper.getMainLooper()); h.post(() -> { throw new RuntimeException("exception on the man thread"); }); // If the flag isn't set to true, then the looper would be dead, so don't do it. if (RavenwoodRuntimeEnvironmentController.TOLERATE_UNHANDLED_EXCEPTIONS) { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); ensureMainThreadAlive(); } else { // waitForIdleSync() won't work, so just wait for a bit... Thread.sleep(5_000); } } } }