Add TestPlayerRunHelper run(player).untilBackgroundThreadCondition(..)
This method is useful for cases where the target condition can become true outside of a message on the main thread. To ensure we don't execute the rest of the test method in parallel with other code, we have to introduce artifical messages on the main thread that check the target condition. PiperOrigin-RevId: 628072444
This commit is contained in:
parent
00ce572a4f
commit
13a3aa7e77
@ -63,6 +63,12 @@ public final class RobolectricUtil {
|
||||
*
|
||||
* <p>Must be called on the main test thread.
|
||||
*
|
||||
* <p>Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes
|
||||
* outside of a main {@link Looper} message, for example because it's checking a volatile variable
|
||||
* or shared synchronized state that is updated on a background thread, or because checking the
|
||||
* condition itself may cause it to become true, then the remainder of the test method may be
|
||||
* executed in parallel with other background thread messages.
|
||||
*
|
||||
* @param condition The condition.
|
||||
* @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded.
|
||||
*/
|
||||
@ -76,6 +82,12 @@ public final class RobolectricUtil {
|
||||
*
|
||||
* <p>Must be called on the main test thread.
|
||||
*
|
||||
* <p>Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes
|
||||
* outside of a main {@link Looper} message, for example because it's checking a volatile variable
|
||||
* or shared synchronized state that is updated on a background thread, or because checking the
|
||||
* condition itself may cause it to become true, then the remainder of the test method may be
|
||||
* executed in parallel with other background thread messages.
|
||||
*
|
||||
* @param condition The condition.
|
||||
* @param timeoutMs The timeout in milliseconds.
|
||||
* @param clock The {@link Clock} to measure the timeout.
|
||||
@ -91,6 +103,12 @@ public final class RobolectricUtil {
|
||||
*
|
||||
* <p>Must be called on the thread corresponding to the {@code looper}.
|
||||
*
|
||||
* <p>Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes
|
||||
* outside of a message on this {@code Looper}, for example because it's checking a volatile
|
||||
* variable or shared synchronized state that is updated on a background thread, or because
|
||||
* checking the condition itself may cause it to become true, then the remainder of the test
|
||||
* method may be executed in parallel with other background thread messages.
|
||||
*
|
||||
* @param looper The {@link Looper}.
|
||||
* @param condition The condition.
|
||||
* @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded.
|
||||
@ -105,6 +123,12 @@ public final class RobolectricUtil {
|
||||
*
|
||||
* <p>Must be called on the thread corresponding to the {@code looper}.
|
||||
*
|
||||
* <p>Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes
|
||||
* outside of a message on this {@code Looper}, for example because it's checking a volatile
|
||||
* variable or shared synchronized state that is updated on a background thread, or because
|
||||
* checking the condition itself may cause it to become true, then the remainder of the test
|
||||
* method may be executed in parallel with other background thread messages.
|
||||
*
|
||||
* @param looper The {@link Looper}.
|
||||
* @param condition The condition.
|
||||
* @param timeoutMs The timeout in milliseconds.
|
||||
|
@ -26,6 +26,7 @@ import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.ConditionVariable;
|
||||
import androidx.media3.common.util.HandlerWrapper;
|
||||
import androidx.media3.common.util.NullableType;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
@ -411,6 +412,47 @@ public final class TestPlayerRunHelper {
|
||||
runMainLooperUntil(receivedMessageCallback::get);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs tasks of the main {@link Looper} until the specified condition becomes true independent
|
||||
* of a message on the main {@link Looper}.
|
||||
*
|
||||
* <p>This method is useful for cases where the condition may change outside of a main {@link
|
||||
* Looper} message, for example because it's checking a volatile variable or shared synchronized
|
||||
* state that is updated on a background thread, or because checking the condition itself may
|
||||
* cause it to become true.
|
||||
*
|
||||
* <p>This method ensures the condition is checked within artificially created main {@link
|
||||
* Looper} messages. When using a {@link androidx.media3.test.utils.FakeClock}, this guarantees
|
||||
* the remainder of the test method is not executed in parallel with other background thread
|
||||
* messages.
|
||||
*
|
||||
* @param backgroundThreadCondition The condition to wait for.
|
||||
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
|
||||
* exceeded.
|
||||
*/
|
||||
public void untilBackgroundThreadCondition(Supplier<Boolean> backgroundThreadCondition)
|
||||
throws Exception {
|
||||
if (backgroundThreadCondition.get()) {
|
||||
return;
|
||||
}
|
||||
AtomicBoolean conditionTrue = new AtomicBoolean();
|
||||
HandlerWrapper handler =
|
||||
player.getClock().createHandler(Util.getCurrentOrMainLooper(), /* callback= */ null);
|
||||
Runnable checkCondition =
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (backgroundThreadCondition.get()) {
|
||||
conditionTrue.set(true);
|
||||
} else {
|
||||
handler.postDelayed(this, /* delayMs= */ 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
handler.post(checkCondition);
|
||||
runUntil(conditionTrue::get);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExoPlayerRunResult ignoringNonFatalErrors() {
|
||||
checkState(!hasBeenUsed);
|
||||
|
Loading…
x
Reference in New Issue
Block a user