Commit d700627e by ibaker Committed by kim-vde

Move Robolectric-related test utils methods to robolectricutils module

This moves TestUtil#runMainLooperUntil and
TestUtil#createRobolectricConditionVariable to a new RobolectricUtil
class.

Also move testutil classes that use Robolectric-related utils classes
(e.g. TestPlayerRunHelper, TestDownloadManagerListener).

PiperOrigin-RevId: 336864959
parent 9e1c6321
Showing with 137 additions and 144 deletions
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilStartOfWindow;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPlaybackState;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilReceiveOffloadSchedulingEnabledNewState;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilSleepingForOffload;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilTimelineChanged;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM; import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample; import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.android.exoplayer2.testutil.TestPlayerRunHelper.playUntilStartOfWindow;
import static com.google.android.exoplayer2.testutil.TestPlayerRunHelper.runUntilPlaybackState;
import static com.google.android.exoplayer2.testutil.TestPlayerRunHelper.runUntilReceiveOffloadSchedulingEnabledNewState;
import static com.google.android.exoplayer2.testutil.TestPlayerRunHelper.runUntilSleepingForOffload;
import static com.google.android.exoplayer2.testutil.TestPlayerRunHelper.runUntilTimelineChanged;
import static com.google.android.exoplayer2.testutil.TestUtil.runMainLooperUntil;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
...@@ -58,6 +58,7 @@ import com.google.android.exoplayer2.drm.DrmSessionEventListener; ...@@ -58,6 +58,7 @@ import com.google.android.exoplayer2.drm.DrmSessionEventListener;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.robolectric.TestPlayerRunHelper;
import com.google.android.exoplayer2.source.ClippingMediaSource; import com.google.android.exoplayer2.source.ClippingMediaSource;
import com.google.android.exoplayer2.source.CompositeMediaSource; import com.google.android.exoplayer2.source.CompositeMediaSource;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
...@@ -97,7 +98,6 @@ import com.google.android.exoplayer2.testutil.FakeTrackSelection; ...@@ -97,7 +98,6 @@ import com.google.android.exoplayer2.testutil.FakeTrackSelection;
import com.google.android.exoplayer2.testutil.FakeTrackSelector; import com.google.android.exoplayer2.testutil.FakeTrackSelector;
import com.google.android.exoplayer2.testutil.NoUidTimeline; import com.google.android.exoplayer2.testutil.NoUidTimeline;
import com.google.android.exoplayer2.testutil.TestExoPlayerBuilder; import com.google.android.exoplayer2.testutil.TestExoPlayerBuilder;
import com.google.android.exoplayer2.testutil.TestPlayerRunHelper;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
......
...@@ -27,8 +27,8 @@ import com.google.android.exoplayer2.MediaItem; ...@@ -27,8 +27,8 @@ import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.robolectric.RandomizedMp3Decoder; import com.google.android.exoplayer2.robolectric.RandomizedMp3Decoder;
import com.google.android.exoplayer2.robolectric.TestPlayerRunHelper;
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock; import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
import com.google.android.exoplayer2.testutil.TestPlayerRunHelper;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
......
...@@ -25,9 +25,9 @@ import com.google.android.exoplayer2.Player; ...@@ -25,9 +25,9 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.robolectric.PlaybackOutput; import com.google.android.exoplayer2.robolectric.PlaybackOutput;
import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig; import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig;
import com.google.android.exoplayer2.robolectric.TestPlayerRunHelper;
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock; import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.testutil.DumpFileAsserts;
import com.google.android.exoplayer2.testutil.TestPlayerRunHelper;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
......
...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.Player; ...@@ -23,9 +23,9 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.robolectric.PlaybackOutput; import com.google.android.exoplayer2.robolectric.PlaybackOutput;
import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig; import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig;
import com.google.android.exoplayer2.robolectric.TestPlayerRunHelper;
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock; import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.testutil.DumpFileAsserts;
import com.google.android.exoplayer2.testutil.TestPlayerRunHelper;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.robolectric.RobolectricUtil.createRobolectricConditionVariable;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
...@@ -24,11 +25,11 @@ import androidx.annotation.Nullable; ...@@ -24,11 +25,11 @@ import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.robolectric.TestDownloadManagerListener;
import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DownloadBuilder; import com.google.android.exoplayer2.testutil.DownloadBuilder;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable; import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ConditionVariable; import com.google.android.exoplayer2.util.ConditionVariable;
...@@ -834,10 +835,10 @@ public class DownloadManagerTest { ...@@ -834,10 +835,10 @@ public class DownloadManagerTest {
private FakeDownloader(DownloadRequest request) { private FakeDownloader(DownloadRequest request) {
this.request = request; this.request = request;
downloadStarted = TestUtil.createRobolectricConditionVariable(); downloadStarted = createRobolectricConditionVariable();
removeStarted = TestUtil.createRobolectricConditionVariable(); removeStarted = createRobolectricConditionVariable();
finished = TestUtil.createRobolectricConditionVariable(); finished = createRobolectricConditionVariable();
blocker = TestUtil.createRobolectricConditionVariable(); blocker = createRobolectricConditionVariable();
startCount = new AtomicInteger(); startCount = new AtomicInteger();
bytesDownloaded = new AtomicInteger(); bytesDownloaded = new AtomicInteger();
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import static com.google.android.exoplayer2.testutil.TestUtil.runMainLooperUntil; import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
......
...@@ -26,9 +26,9 @@ import com.google.android.exoplayer2.Player; ...@@ -26,9 +26,9 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.robolectric.PlaybackOutput; import com.google.android.exoplayer2.robolectric.PlaybackOutput;
import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig; import com.google.android.exoplayer2.robolectric.ShadowMediaCodecConfig;
import com.google.android.exoplayer2.robolectric.TestPlayerRunHelper;
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock; import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.testutil.DumpFileAsserts;
import com.google.android.exoplayer2.testutil.TestPlayerRunHelper;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
......
...@@ -31,13 +31,13 @@ import com.google.android.exoplayer2.offline.DefaultDownloaderFactory; ...@@ -31,13 +31,13 @@ import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.robolectric.TestDownloadManagerListener;
import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.CacheAsserts.RequestSet; import com.google.android.exoplayer2.testutil.CacheAsserts.RequestSet;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable; import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource.Factory; import com.google.android.exoplayer2.upstream.DataSource.Factory;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource; import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
......
...@@ -34,11 +34,11 @@ import com.google.android.exoplayer2.offline.DownloadManager; ...@@ -34,11 +34,11 @@ import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.DownloadService; import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.robolectric.TestDownloadManagerListener;
import com.google.android.exoplayer2.scheduler.Scheduler; import com.google.android.exoplayer2.scheduler.Scheduler;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource; import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
......
/*
* Copyright (C) 2020 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.google.android.exoplayer2.robolectric;
import android.os.Looper;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.SystemClock;
import com.google.common.base.Supplier;
import java.util.concurrent.TimeoutException;
import org.robolectric.shadows.ShadowLooper;
/** Utility methods for Robolectric-based tests. */
public final class RobolectricUtil {
private RobolectricUtil() {}
/**
* The default timeout applied when calling {@link #runMainLooperUntil(Supplier)}. This timeout
* should be sufficient for any condition using a Robolectric test.
*/
public static final long DEFAULT_TIMEOUT_MS = 10_000;
/**
* Creates a {@link ConditionVariable} whose {@link ConditionVariable#block(long)} method times
* out according to wallclock time when used in Robolectric tests.
*/
public static ConditionVariable createRobolectricConditionVariable() {
return new ConditionVariable(
new SystemClock() {
@Override
public long elapsedRealtime() {
// elapsedRealtime() does not advance during Robolectric test execution, so use
// currentTimeMillis() instead. This is technically unsafe because this clock is not
// guaranteed to be monotonic, but in practice it will work provided the clock of the
// host machine does not change during test execution.
return Clock.DEFAULT.currentTimeMillis();
}
});
}
/**
* Runs tasks of the main Robolectric {@link Looper} until the {@code condition} returns {@code
* true}.
*
* <p>Must be called on the main test thread.
*
* @param condition The condition.
* @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded.
*/
public static void runMainLooperUntil(Supplier<Boolean> condition) throws TimeoutException {
runMainLooperUntil(condition, DEFAULT_TIMEOUT_MS, Clock.DEFAULT);
}
/**
* Runs tasks of the main Robolectric {@link Looper} until the {@code condition} returns {@code
* true}.
*
* @param condition The condition.
* @param timeoutMs The timeout in milliseconds.
* @param clock The {@link Clock} to measure the timeout.
* @throws TimeoutException If the {@code timeoutMs timeout} is exceeded.
*/
public static void runMainLooperUntil(Supplier<Boolean> condition, long timeoutMs, Clock clock)
throws TimeoutException {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException();
}
long timeoutTimeMs = clock.currentTimeMillis() + timeoutMs;
while (!condition.get()) {
if (clock.currentTimeMillis() >= timeoutTimeMs) {
throw new TimeoutException();
}
ShadowLooper.runMainLooperOneTask();
}
}
}
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.robolectric;
import static com.google.android.exoplayer2.robolectric.RobolectricUtil.createRobolectricConditionVariable;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
...@@ -46,8 +47,8 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen ...@@ -46,8 +47,8 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
public TestDownloadManagerListener(DownloadManager downloadManager) { public TestDownloadManagerListener(DownloadManager downloadManager) {
this.downloadManager = downloadManager; this.downloadManager = downloadManager;
downloadStates = new HashMap<>(); downloadStates = new HashMap<>();
initializedCondition = TestUtil.createRobolectricConditionVariable(); initializedCondition = createRobolectricConditionVariable();
idleCondition = TestUtil.createRobolectricConditionVariable(); idleCondition = createRobolectricConditionVariable();
downloadManager.addListener(this); downloadManager.addListener(this);
} }
...@@ -61,7 +62,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen ...@@ -61,7 +62,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
idleCondition.close(); idleCondition.close();
// If the manager is already idle the condition will be opened by the code immediately below. // If the manager is already idle the condition will be opened by the code immediately below.
// Else it will be opened by onIdle(). // Else it will be opened by onIdle().
ConditionVariable checkedOnMainThread = TestUtil.createRobolectricConditionVariable(); ConditionVariable checkedOnMainThread = createRobolectricConditionVariable();
new Handler(downloadManager.getApplicationLooper()) new Handler(downloadManager.getApplicationLooper())
.post( .post(
() -> { () -> {
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.robolectric;
import static com.google.android.exoplayer2.testutil.TestUtil.runMainLooperUntil; import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
...@@ -48,7 +48,7 @@ public class TestPlayerRunHelper { ...@@ -48,7 +48,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedState The expected {@link Player.State}. * @param expectedState The expected {@link Player.State}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilPlaybackState(Player player, @Player.State int expectedState) public static void runUntilPlaybackState(Player player, @Player.State int expectedState)
...@@ -78,7 +78,7 @@ public class TestPlayerRunHelper { ...@@ -78,7 +78,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedPlayWhenReady The expected value for {@link Player#getPlayWhenReady()}. * @param expectedPlayWhenReady The expected value for {@link Player#getPlayWhenReady()}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilPlayWhenReady(Player player, boolean expectedPlayWhenReady) public static void runUntilPlayWhenReady(Player player, boolean expectedPlayWhenReady)
...@@ -108,7 +108,7 @@ public class TestPlayerRunHelper { ...@@ -108,7 +108,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedTimeline The expected {@link Timeline}. * @param expectedTimeline The expected {@link Timeline}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilTimelineChanged(Player player, Timeline expectedTimeline) public static void runUntilTimelineChanged(Player player, Timeline expectedTimeline)
...@@ -137,7 +137,7 @@ public class TestPlayerRunHelper { ...@@ -137,7 +137,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @return The new {@link Timeline}. * @return The new {@link Timeline}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static Timeline runUntilTimelineChanged(Player player) throws TimeoutException { public static Timeline runUntilTimelineChanged(Player player) throws TimeoutException {
...@@ -163,7 +163,7 @@ public class TestPlayerRunHelper { ...@@ -163,7 +163,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedReason The expected {@link Player.DiscontinuityReason}. * @param expectedReason The expected {@link Player.DiscontinuityReason}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilPositionDiscontinuity( public static void runUntilPositionDiscontinuity(
...@@ -189,7 +189,7 @@ public class TestPlayerRunHelper { ...@@ -189,7 +189,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @return The raised {@link ExoPlaybackException}. * @return The raised {@link ExoPlaybackException}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static ExoPlaybackException runUntilError(Player player) throws TimeoutException { public static ExoPlaybackException runUntilError(Player player) throws TimeoutException {
...@@ -214,7 +214,7 @@ public class TestPlayerRunHelper { ...@@ -214,7 +214,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @return The new offloadSchedulingEnabled state. * @return The new offloadSchedulingEnabled state.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(Player player) public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(Player player)
...@@ -241,7 +241,7 @@ public class TestPlayerRunHelper { ...@@ -241,7 +241,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedSleepForOffload The expected sleep of offload state. * @param expectedSleepForOffload The expected sleep of offload state.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilSleepingForOffload(Player player, boolean expectedSleepForOffload) public static void runUntilSleepingForOffload(Player player, boolean expectedSleepForOffload)
...@@ -266,7 +266,7 @@ public class TestPlayerRunHelper { ...@@ -266,7 +266,7 @@ public class TestPlayerRunHelper {
* callback has been called. * callback has been called.
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilRenderedFirstFrame(SimpleExoPlayer player) throws TimeoutException { public static void runUntilRenderedFirstFrame(SimpleExoPlayer player) throws TimeoutException {
...@@ -291,7 +291,7 @@ public class TestPlayerRunHelper { ...@@ -291,7 +291,7 @@ public class TestPlayerRunHelper {
* @param player The {@link Player}. * @param player The {@link Player}.
* @param windowIndex The window. * @param windowIndex The window.
* @param positionMs The position within the window, in milliseconds. * @param positionMs The position within the window, in milliseconds.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void playUntilPosition(ExoPlayer player, int windowIndex, long positionMs) public static void playUntilPosition(ExoPlayer player, int windowIndex, long positionMs)
...@@ -329,7 +329,7 @@ public class TestPlayerRunHelper { ...@@ -329,7 +329,7 @@ public class TestPlayerRunHelper {
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param windowIndex The window. * @param windowIndex The window.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void playUntilStartOfWindow(ExoPlayer player, int windowIndex) public static void playUntilStartOfWindow(ExoPlayer player, int windowIndex)
...@@ -342,7 +342,7 @@ public class TestPlayerRunHelper { ...@@ -342,7 +342,7 @@ public class TestPlayerRunHelper {
* commands on the internal playback thread. * commands on the internal playback thread.
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilPendingCommandsAreFullyHandled(ExoPlayer player) public static void runUntilPendingCommandsAreFullyHandled(ExoPlayer player)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.robolectric;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
...@@ -31,14 +31,13 @@ import java.util.concurrent.TimeoutException; ...@@ -31,14 +31,13 @@ import java.util.concurrent.TimeoutException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Unit test for {@link TestUtil}. */ /** Unit test for {@link RobolectricUtil}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TestUtilTest { public class RobolectricUtilTest {
@Test @Test
public void createRobolectricConditionVariable_blockWithTimeout_timesOut() public void createRobolectricConditionVariable_blockWithTimeout_timesOut()
throws InterruptedException { throws InterruptedException {
ConditionVariable conditionVariable = TestUtil.createRobolectricConditionVariable(); ConditionVariable conditionVariable = RobolectricUtil.createRobolectricConditionVariable();
assertThat(conditionVariable.block(/* timeoutMs= */ 1)).isFalse(); assertThat(conditionVariable.block(/* timeoutMs= */ 1)).isFalse();
assertThat(conditionVariable.isOpen()).isFalse(); assertThat(conditionVariable.isOpen()).isFalse();
} }
...@@ -46,7 +45,7 @@ public class TestUtilTest { ...@@ -46,7 +45,7 @@ public class TestUtilTest {
@Test @Test
public void createRobolectricConditionVariable_blockWithTimeout_blocksForAtLeastTimeout() public void createRobolectricConditionVariable_blockWithTimeout_blocksForAtLeastTimeout()
throws InterruptedException { throws InterruptedException {
ConditionVariable conditionVariable = TestUtil.createRobolectricConditionVariable(); ConditionVariable conditionVariable = RobolectricUtil.createRobolectricConditionVariable();
long startTimeMs = System.currentTimeMillis(); long startTimeMs = System.currentTimeMillis();
assertThat(conditionVariable.block(/* timeoutMs= */ 500)).isFalse(); assertThat(conditionVariable.block(/* timeoutMs= */ 500)).isFalse();
long endTimeMs = System.currentTimeMillis(); long endTimeMs = System.currentTimeMillis();
...@@ -57,7 +56,7 @@ public class TestUtilTest { ...@@ -57,7 +56,7 @@ public class TestUtilTest {
public void runMainLooperUntil_withConditionAlreadyTrue_returnsImmediately() throws Exception { public void runMainLooperUntil_withConditionAlreadyTrue_returnsImmediately() throws Exception {
Clock mockClock = mock(Clock.class); Clock mockClock = mock(Clock.class);
TestUtil.runMainLooperUntil(() -> true, /* timeoutMs= */ 0, mockClock); RobolectricUtil.runMainLooperUntil(() -> true, /* timeoutMs= */ 0, mockClock);
verify(mockClock, atMost(1)).currentTimeMillis(); verify(mockClock, atMost(1)).currentTimeMillis();
} }
...@@ -69,7 +68,7 @@ public class TestUtilTest { ...@@ -69,7 +68,7 @@ public class TestUtilTest {
assertThrows( assertThrows(
TimeoutException.class, TimeoutException.class,
() -> TestUtil.runMainLooperUntil(() -> false, /* timeoutMs= */ 42, mockClock)); () -> RobolectricUtil.runMainLooperUntil(() -> false, /* timeoutMs= */ 42, mockClock));
verify(mockClock, times(3)).currentTimeMillis(); verify(mockClock, times(3)).currentTimeMillis();
} }
...@@ -87,7 +86,7 @@ public class TestUtilTest { ...@@ -87,7 +86,7 @@ public class TestUtilTest {
.thenReturn(false) .thenReturn(false)
.thenReturn(true); .thenReturn(true);
TestUtil.runMainLooperUntil(mockCondition, /* timeoutMs= */ 5674, mock(Clock.class)); RobolectricUtil.runMainLooperUntil(mockCondition, /* timeoutMs= */ 5674, mock(Clock.class));
verify(mockCondition, times(5)).get(); verify(mockCondition, times(5)).get();
} }
......
...@@ -25,7 +25,6 @@ import android.graphics.BitmapFactory; ...@@ -25,7 +25,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.net.Uri; import android.net.Uri;
import android.os.Looper;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.DefaultDatabaseProvider; import com.google.android.exoplayer2.database.DefaultDatabaseProvider;
...@@ -38,41 +37,21 @@ import com.google.android.exoplayer2.metadata.MetadataInputBuffer; ...@@ -38,41 +37,21 @@ import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.SystemClock;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeoutException;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Utility methods for tests. * Utility methods for tests.
*/ */
public class TestUtil { public class TestUtil {
/**
* The default timeout applied when calling {@link #runMainLooperUntil(Supplier)}. This timeout
* should be sufficient for any condition using a Robolectric test.
*/
public static final long DEFAULT_TIMEOUT_MS = 10_000;
/** Reflectively loaded Robolectric ShadowLooper#runOneTask. */
private static @MonotonicNonNull Object shadowLooper;
private static @MonotonicNonNull Method runOneTaskMethod;
private TestUtil() {} private TestUtil() {}
/** /**
...@@ -457,81 +436,4 @@ public class TestUtil { ...@@ -457,81 +436,4 @@ public class TestUtil {
return buffer; return buffer;
} }
/**
* Creates a {@link ConditionVariable} whose {@link ConditionVariable#block(long)} method times
* out according to wallclock time when used in Robolectric tests.
*/
public static ConditionVariable createRobolectricConditionVariable() {
return new ConditionVariable(
new SystemClock() {
@Override
public long elapsedRealtime() {
// elapsedRealtime() does not advance during Robolectric test execution, so use
// currentTimeMillis() instead. This is technically unsafe because this clock is not
// guaranteed to be monotonic, but in practice it will work provided the clock of the
// host machine does not change during test execution.
return Clock.DEFAULT.currentTimeMillis();
}
});
}
/**
* Runs tasks of the main Robolectric {@link Looper} until the {@code condition} returns {@code
* true}.
*
* <p>Must be called on the main test thread.
*
* @param condition The condition.
* @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded.
*/
public static void runMainLooperUntil(Supplier<Boolean> condition) throws TimeoutException {
runMainLooperUntil(condition, DEFAULT_TIMEOUT_MS, Clock.DEFAULT);
}
/**
* Runs tasks of the main Robolectric {@link Looper} until the {@code condition} returns {@code
* true}.
*
* @param condition The condition.
* @param timeoutMs The timeout in milliseconds.
* @param clock The {@link Clock} to measure the timeout.
* @throws TimeoutException If the {@code timeoutMs timeout} is exceeded.
*/
public static void runMainLooperUntil(Supplier<Boolean> condition, long timeoutMs, Clock clock)
throws TimeoutException {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException();
}
maybeInitShadowLooperAndRunOneTaskMethod();
try {
long timeoutTimeMs = clock.currentTimeMillis() + timeoutMs;
while (!condition.get()) {
if (clock.currentTimeMillis() >= timeoutTimeMs) {
throw new TimeoutException();
}
runOneTaskMethod.invoke(shadowLooper);
}
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e.getCause());
}
}
@EnsuresNonNull({"shadowLooper", "runOneTaskMethod"})
private static void maybeInitShadowLooperAndRunOneTaskMethod() {
if (shadowLooper != null && runOneTaskMethod != null) {
return;
}
try {
Class<?> clazz = Class.forName("org.robolectric.Shadows");
Method shadowOfMethod =
Assertions.checkNotNull(clazz.getDeclaredMethod("shadowOf", Looper.class));
shadowLooper =
Assertions.checkNotNull(shadowOfMethod.invoke(new Object(), Looper.getMainLooper()));
runOneTaskMethod = shadowLooper.getClass().getDeclaredMethod("runOneTask");
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment