From d700627ec23559f9a88d599b0c4e0c8ddac5aa64 Mon Sep 17 00:00:00 2001 From: ibaker Date: Tue, 13 Oct 2020 14:36:12 +0100 Subject: [PATCH] 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 --- .../android/exoplayer2/ExoPlayerTest.java | 14 +-- .../e2etest/EndToEndGaplessTest.java | 2 +- .../exoplayer2/e2etest/Mp4PlaybackTest.java | 2 +- .../exoplayer2/e2etest/TsPlaybackTest.java | 2 +- .../offline/DownloadManagerTest.java | 11 ++- .../source/ProgressiveMediaPeriodTest.java | 2 +- .../exoplayer2/e2etest/DashPlaybackTest.java | 2 +- .../dash/offline/DownloadManagerDashTest.java | 2 +- .../dash/offline/DownloadServiceDashTest.java | 2 +- .../robolectric/RobolectricUtil.java | 90 +++++++++++++++++ .../TestDownloadManagerListener.java | 9 +- .../robolectric}/TestPlayerRunHelper.java | 28 +++--- .../robolectric/RobolectricUtilTest.java | 17 ++-- .../android/exoplayer2/testutil/TestUtil.java | 98 ------------------- 14 files changed, 137 insertions(+), 144 deletions(-) create mode 100644 robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/RobolectricUtil.java rename {testutils/src/main/java/com/google/android/exoplayer2/testutil => robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric}/TestDownloadManagerListener.java (93%) rename {testutils/src/main/java/com/google/android/exoplayer2/testutil => robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric}/TestPlayerRunHelper.java (90%) rename testutils/src/test/java/com/google/android/exoplayer2/testutil/TestUtilTest.java => robolectricutils/src/test/java/com/google/android/exoplayer2/robolectric/RobolectricUtilTest.java (82%) diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index 47fb993299..d6ed7ac107 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -15,14 +15,14 @@ */ 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.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 org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertThrows; @@ -58,6 +58,7 @@ import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.metadata.Metadata; 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.CompositeMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource; @@ -97,7 +98,6 @@ import com.google.android.exoplayer2.testutil.FakeTrackSelection; import com.google.android.exoplayer2.testutil.FakeTrackSelector; import com.google.android.exoplayer2.testutil.NoUidTimeline; 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.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/EndToEndGaplessTest.java b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/EndToEndGaplessTest.java index 3497b06834..7319d1576c 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/EndToEndGaplessTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/EndToEndGaplessTest.java @@ -27,8 +27,8 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; 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.TestPlayerRunHelper; import com.google.android.exoplayer2.util.Assertions; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Bytes; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/Mp4PlaybackTest.java b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/Mp4PlaybackTest.java index 85fcae4383..aa50b16003 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/Mp4PlaybackTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/Mp4PlaybackTest.java @@ -25,9 +25,9 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.robolectric.PlaybackOutput; 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.DumpFileAsserts; -import com.google.android.exoplayer2.testutil.TestPlayerRunHelper; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/TsPlaybackTest.java b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/TsPlaybackTest.java index 8db6f668d4..4dee97a824 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/TsPlaybackTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/TsPlaybackTest.java @@ -23,9 +23,9 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.robolectric.PlaybackOutput; 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.DumpFileAsserts; -import com.google.android.exoplayer2.testutil.TestPlayerRunHelper; import com.google.common.collect.ImmutableList; import org.junit.Rule; import org.junit.Test; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java index d5959584ad..1444b0484c 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java @@ -15,6 +15,7 @@ */ 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 java.util.Arrays.asList; @@ -24,11 +25,11 @@ import androidx.annotation.Nullable; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; 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.testutil.DownloadBuilder; import com.google.android.exoplayer2.testutil.DummyMainThread; 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.util.Assertions; import com.google.android.exoplayer2.util.ConditionVariable; @@ -834,10 +835,10 @@ public class DownloadManagerTest { private FakeDownloader(DownloadRequest request) { this.request = request; - downloadStarted = TestUtil.createRobolectricConditionVariable(); - removeStarted = TestUtil.createRobolectricConditionVariable(); - finished = TestUtil.createRobolectricConditionVariable(); - blocker = TestUtil.createRobolectricConditionVariable(); + downloadStarted = createRobolectricConditionVariable(); + removeStarted = createRobolectricConditionVariable(); + finished = createRobolectricConditionVariable(); + blocker = createRobolectricConditionVariable(); startCount = new AtomicInteger(); bytesDownloaded = new AtomicInteger(); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriodTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriodTest.java index ecdb43f150..90b29b30d5 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriodTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriodTest.java @@ -15,7 +15,7 @@ */ 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 android.net.Uri; diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/e2etest/DashPlaybackTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/e2etest/DashPlaybackTest.java index 0400eeb640..fc7f697cca 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/e2etest/DashPlaybackTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/e2etest/DashPlaybackTest.java @@ -26,9 +26,9 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.robolectric.PlaybackOutput; 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.DumpFileAsserts; -import com.google.android.exoplayer2.testutil.TestPlayerRunHelper; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import org.junit.Rule; import org.junit.Test; diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java index 2993bb4442..6bdc84438b 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java @@ -31,13 +31,13 @@ import com.google.android.exoplayer2.offline.DefaultDownloaderFactory; import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadRequest; 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.testutil.CacheAsserts.RequestSet; import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable; import com.google.android.exoplayer2.testutil.FakeDataSet; 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.upstream.DataSource.Factory; import com.google.android.exoplayer2.upstream.cache.CacheDataSource; diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java index 6b528cdd82..98a7f6e887 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java @@ -34,11 +34,11 @@ import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadService; 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.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.FakeDataSet; 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.upstream.DataSource; import com.google.android.exoplayer2.upstream.cache.CacheDataSource; diff --git a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/RobolectricUtil.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/RobolectricUtil.java new file mode 100644 index 0000000000..0374559be9 --- /dev/null +++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/RobolectricUtil.java @@ -0,0 +1,90 @@ +/* + * 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}. + * + *

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 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 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(); + } + } +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestDownloadManagerListener.java similarity index 93% rename from testutils/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java rename to robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestDownloadManagerListener.java index 6fa7ebe741..493e95cb09 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java +++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestDownloadManagerListener.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * 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 java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.fail; @@ -46,8 +47,8 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen public TestDownloadManagerListener(DownloadManager downloadManager) { this.downloadManager = downloadManager; downloadStates = new HashMap<>(); - initializedCondition = TestUtil.createRobolectricConditionVariable(); - idleCondition = TestUtil.createRobolectricConditionVariable(); + initializedCondition = createRobolectricConditionVariable(); + idleCondition = createRobolectricConditionVariable(); downloadManager.addListener(this); } @@ -61,7 +62,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen idleCondition.close(); // If the manager is already idle the condition will be opened by the code immediately below. // Else it will be opened by onIdle(). - ConditionVariable checkedOnMainThread = TestUtil.createRobolectricConditionVariable(); + ConditionVariable checkedOnMainThread = createRobolectricConditionVariable(); new Handler(downloadManager.getApplicationLooper()) .post( () -> { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestPlayerRunHelper.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java similarity index 90% rename from testutils/src/main/java/com/google/android/exoplayer2/testutil/TestPlayerRunHelper.java rename to robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java index 6a2be5e03a..55a55ab059 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestPlayerRunHelper.java +++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java @@ -14,9 +14,9 @@ * 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.Looper; @@ -48,7 +48,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void runUntilPlaybackState(Player player, @Player.State int expectedState) @@ -78,7 +78,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void runUntilPlayWhenReady(Player player, boolean expectedPlayWhenReady) @@ -108,7 +108,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void runUntilTimelineChanged(Player player, Timeline expectedTimeline) @@ -137,7 +137,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static Timeline runUntilTimelineChanged(Player player) throws TimeoutException { @@ -163,7 +163,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void runUntilPositionDiscontinuity( @@ -189,7 +189,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static ExoPlaybackException runUntilError(Player player) throws TimeoutException { @@ -214,7 +214,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(Player player) @@ -241,7 +241,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void runUntilSleepingForOffload(Player player, boolean expectedSleepForOffload) @@ -266,7 +266,7 @@ public class TestPlayerRunHelper { * callback has been called. * * @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. */ public static void runUntilRenderedFirstFrame(SimpleExoPlayer player) throws TimeoutException { @@ -291,7 +291,7 @@ public class TestPlayerRunHelper { * @param player The {@link Player}. * @param windowIndex The window. * @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. */ public static void playUntilPosition(ExoPlayer player, int windowIndex, long positionMs) @@ -329,7 +329,7 @@ public class TestPlayerRunHelper { * * @param player The {@link Player}. * @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. */ public static void playUntilStartOfWindow(ExoPlayer player, int windowIndex) @@ -342,7 +342,7 @@ public class TestPlayerRunHelper { * commands on the internal playback thread. * * @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. */ public static void runUntilPendingCommandsAreFullyHandled(ExoPlayer player) diff --git a/testutils/src/test/java/com/google/android/exoplayer2/testutil/TestUtilTest.java b/robolectricutils/src/test/java/com/google/android/exoplayer2/robolectric/RobolectricUtilTest.java similarity index 82% rename from testutils/src/test/java/com/google/android/exoplayer2/testutil/TestUtilTest.java rename to robolectricutils/src/test/java/com/google/android/exoplayer2/robolectric/RobolectricUtilTest.java index cc7df84375..08d1a2ae2b 100644 --- a/testutils/src/test/java/com/google/android/exoplayer2/testutil/TestUtilTest.java +++ b/robolectricutils/src/test/java/com/google/android/exoplayer2/robolectric/RobolectricUtilTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * 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 org.junit.Assert.assertThrows; @@ -31,14 +31,13 @@ import java.util.concurrent.TimeoutException; import org.junit.Test; import org.junit.runner.RunWith; -/** Unit test for {@link TestUtil}. */ +/** Unit test for {@link RobolectricUtil}. */ @RunWith(AndroidJUnit4.class) -public class TestUtilTest { - +public class RobolectricUtilTest { @Test public void createRobolectricConditionVariable_blockWithTimeout_timesOut() throws InterruptedException { - ConditionVariable conditionVariable = TestUtil.createRobolectricConditionVariable(); + ConditionVariable conditionVariable = RobolectricUtil.createRobolectricConditionVariable(); assertThat(conditionVariable.block(/* timeoutMs= */ 1)).isFalse(); assertThat(conditionVariable.isOpen()).isFalse(); } @@ -46,7 +45,7 @@ public class TestUtilTest { @Test public void createRobolectricConditionVariable_blockWithTimeout_blocksForAtLeastTimeout() throws InterruptedException { - ConditionVariable conditionVariable = TestUtil.createRobolectricConditionVariable(); + ConditionVariable conditionVariable = RobolectricUtil.createRobolectricConditionVariable(); long startTimeMs = System.currentTimeMillis(); assertThat(conditionVariable.block(/* timeoutMs= */ 500)).isFalse(); long endTimeMs = System.currentTimeMillis(); @@ -57,7 +56,7 @@ public class TestUtilTest { public void runMainLooperUntil_withConditionAlreadyTrue_returnsImmediately() throws Exception { Clock mockClock = mock(Clock.class); - TestUtil.runMainLooperUntil(() -> true, /* timeoutMs= */ 0, mockClock); + RobolectricUtil.runMainLooperUntil(() -> true, /* timeoutMs= */ 0, mockClock); verify(mockClock, atMost(1)).currentTimeMillis(); } @@ -69,7 +68,7 @@ public class TestUtilTest { assertThrows( TimeoutException.class, - () -> TestUtil.runMainLooperUntil(() -> false, /* timeoutMs= */ 42, mockClock)); + () -> RobolectricUtil.runMainLooperUntil(() -> false, /* timeoutMs= */ 42, mockClock)); verify(mockClock, times(3)).currentTimeMillis(); } @@ -87,7 +86,7 @@ public class TestUtilTest { .thenReturn(false) .thenReturn(true); - TestUtil.runMainLooperUntil(mockCondition, /* timeoutMs= */ 5674, mock(Clock.class)); + RobolectricUtil.runMainLooperUntil(mockCondition, /* timeoutMs= */ 5674, mock(Clock.class)); verify(mockCondition, times(5)).get(); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java index 7107c0b8a4..f52f4380cf 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java @@ -25,7 +25,6 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.media.MediaCodec; import android.net.Uri; -import android.os.Looper; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DefaultDatabaseProvider; @@ -38,41 +37,21 @@ import com.google.android.exoplayer2.metadata.MetadataInputBuffer; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; 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.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Bytes; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.ByteBuffer; 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. */ 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() {} /** @@ -457,81 +436,4 @@ public class TestUtil { 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}. - * - *

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 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 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); - } - } }