Stop using SimpleExoPlayer for tests
The class is deprecated and all tests should preferably use the non-deprecated code paths. PiperOrigin-RevId: 428007986
This commit is contained in:
parent
0314d14737
commit
6dae8746ad
@ -65,9 +65,11 @@ import static org.junit.Assert.fail;
|
|||||||
import static org.mockito.AdditionalMatchers.not;
|
import static org.mockito.AdditionalMatchers.not;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.atLeast;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@ -180,7 +182,9 @@ import org.mockito.ArgumentMatcher;
|
|||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowAudioManager;
|
import org.robolectric.shadows.ShadowAudioManager;
|
||||||
|
import org.robolectric.shadows.ShadowLooper;
|
||||||
|
|
||||||
/** Unit test for {@link ExoPlayer}. */
|
/** Unit test for {@link ExoPlayer}. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@ -11468,6 +11472,122 @@ public final class ExoPlayerTest {
|
|||||||
assertThat(player.getMediaMetadata()).isEqualTo(mediaMetadata);
|
assertThat(player.getMediaMetadata()).isEqualTo(mediaMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(sdk = Config.ALL_SDKS)
|
||||||
|
public void builder_inBackgroundThread_doesNotThrow() throws Exception {
|
||||||
|
Thread builderThread =
|
||||||
|
new Thread(
|
||||||
|
() -> new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build());
|
||||||
|
AtomicReference<Throwable> builderThrow = new AtomicReference<>();
|
||||||
|
builderThread.setUncaughtExceptionHandler((thread, throwable) -> builderThrow.set(throwable));
|
||||||
|
|
||||||
|
builderThread.start();
|
||||||
|
builderThread.join();
|
||||||
|
|
||||||
|
assertThat(builderThrow.get()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPlaylistMetadataChanged_calledWhenPlaylistMetadataSet() {
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext()).build();
|
||||||
|
Player.Listener playerListener = mock(Player.Listener.class);
|
||||||
|
player.addListener(playerListener);
|
||||||
|
AnalyticsListener analyticsListener = mock(AnalyticsListener.class);
|
||||||
|
player.addAnalyticsListener(analyticsListener);
|
||||||
|
|
||||||
|
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setTitle("test").build();
|
||||||
|
player.setPlaylistMetadata(mediaMetadata);
|
||||||
|
|
||||||
|
verify(playerListener).onPlaylistMetadataChanged(mediaMetadata);
|
||||||
|
verify(analyticsListener).onPlaylistMetadataChanged(any(), eq(mediaMetadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void release_triggersAllPendingEventsInAnalyticsListeners() throws Exception {
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
|
||||||
|
.setRenderersFactory(
|
||||||
|
(handler, videoListener, audioListener, textOutput, metadataOutput) ->
|
||||||
|
new Renderer[] {new FakeVideoRenderer(handler, videoListener)})
|
||||||
|
.build();
|
||||||
|
AnalyticsListener listener = mock(AnalyticsListener.class);
|
||||||
|
player.addAnalyticsListener(listener);
|
||||||
|
// Do something that requires clean-up callbacks like decoder disabling.
|
||||||
|
player.setMediaSource(
|
||||||
|
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
|
||||||
|
player.prepare();
|
||||||
|
player.play();
|
||||||
|
runUntilPlaybackState(player, Player.STATE_READY);
|
||||||
|
|
||||||
|
player.release();
|
||||||
|
ShadowLooper.runMainLooperToNextTask();
|
||||||
|
|
||||||
|
verify(listener).onVideoDisabled(any(), any());
|
||||||
|
verify(listener).onPlayerReleased(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void releaseAfterRendererEvents_triggersPendingVideoEventsInListener() throws Exception {
|
||||||
|
Surface surface = new Surface(new SurfaceTexture(/* texName= */ 0));
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
|
||||||
|
.setRenderersFactory(
|
||||||
|
(handler, videoListener, audioListener, textOutput, metadataOutput) ->
|
||||||
|
new Renderer[] {new FakeVideoRenderer(handler, videoListener)})
|
||||||
|
.build();
|
||||||
|
Player.Listener listener = mock(Player.Listener.class);
|
||||||
|
player.addListener(listener);
|
||||||
|
player.setMediaSource(
|
||||||
|
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
|
||||||
|
player.setVideoSurface(surface);
|
||||||
|
player.prepare();
|
||||||
|
player.play();
|
||||||
|
runUntilPlaybackState(player, Player.STATE_READY);
|
||||||
|
|
||||||
|
player.release();
|
||||||
|
surface.release();
|
||||||
|
ShadowLooper.runMainLooperToNextTask();
|
||||||
|
|
||||||
|
verify(listener, atLeastOnce()).onEvents(any(), any()); // EventListener
|
||||||
|
verify(listener).onRenderedFirstFrame(); // VideoListener
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void releaseAfterVolumeChanges_triggerPendingVolumeEventInListener() throws Exception {
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext()).build();
|
||||||
|
Player.Listener listener = mock(Player.Listener.class);
|
||||||
|
player.addListener(listener);
|
||||||
|
|
||||||
|
player.setVolume(0F);
|
||||||
|
player.release();
|
||||||
|
ShadowLooper.runMainLooperToNextTask();
|
||||||
|
|
||||||
|
verify(listener).onVolumeChanged(anyFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void releaseAfterVolumeChanges_triggerPendingDeviceVolumeEventsInListener() {
|
||||||
|
ExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext()).build();
|
||||||
|
Player.Listener listener = mock(Player.Listener.class);
|
||||||
|
player.addListener(listener);
|
||||||
|
|
||||||
|
int deviceVolume = player.getDeviceVolume();
|
||||||
|
try {
|
||||||
|
player.setDeviceVolume(deviceVolume + 1); // No-op if at max volume.
|
||||||
|
player.setDeviceVolume(deviceVolume - 1); // No-op if at min volume.
|
||||||
|
} finally {
|
||||||
|
player.setDeviceVolume(deviceVolume); // Restore original volume.
|
||||||
|
}
|
||||||
|
|
||||||
|
player.release();
|
||||||
|
ShadowLooper.runMainLooperToNextTask();
|
||||||
|
|
||||||
|
verify(listener, atLeast(2)).onDeviceVolumeChanged(anyInt(), anyBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
||||||
@ -11587,7 +11707,7 @@ public final class ExoPlayerTest {
|
|||||||
@Override
|
@Override
|
||||||
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||||
super.render(positionUs, elapsedRealtimeUs);
|
super.render(positionUs, elapsedRealtimeUs);
|
||||||
if (sleepOnNextRender.compareAndSet(/* expect= */ true, /* update= */ false)) {
|
if (sleepOnNextRender.compareAndSet(/* expectedValue= */ true, /* newValue= */ false)) {
|
||||||
wakeupListenerReceiver.get().onSleep(WAKEUP_DEADLINE_MS);
|
wakeupListenerReceiver.get().onSleep(WAKEUP_DEADLINE_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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 androidx.media3.exoplayer;
|
|
||||||
|
|
||||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilPlaybackState;
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.atLeast;
|
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
import android.graphics.SurfaceTexture;
|
|
||||||
import android.view.Surface;
|
|
||||||
import androidx.media3.common.MediaMetadata;
|
|
||||||
import androidx.media3.common.Player;
|
|
||||||
import androidx.media3.exoplayer.analytics.AnalyticsListener;
|
|
||||||
import androidx.media3.test.utils.ExoPlayerTestRunner;
|
|
||||||
import androidx.media3.test.utils.FakeClock;
|
|
||||||
import androidx.media3.test.utils.FakeMediaSource;
|
|
||||||
import androidx.media3.test.utils.FakeTimeline;
|
|
||||||
import androidx.media3.test.utils.FakeVideoRenderer;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
import org.robolectric.shadows.ShadowLooper;
|
|
||||||
|
|
||||||
/** Unit test for {@link SimpleExoPlayer}. */
|
|
||||||
@SuppressWarnings("deprecation") // Testing deprecated type.
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class SimpleExoPlayerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Config(sdk = Config.ALL_SDKS)
|
|
||||||
public void builder_inBackgroundThread_doesNotThrow() throws Exception {
|
|
||||||
Thread builderThread =
|
|
||||||
new Thread(
|
|
||||||
() -> new SimpleExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build());
|
|
||||||
AtomicReference<Throwable> builderThrow = new AtomicReference<>();
|
|
||||||
builderThread.setUncaughtExceptionHandler((thread, throwable) -> builderThrow.set(throwable));
|
|
||||||
|
|
||||||
builderThread.start();
|
|
||||||
builderThread.join();
|
|
||||||
|
|
||||||
assertThat(builderThrow.get()).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onPlaylistMetadataChanged_calledWhenPlaylistMetadataSet() {
|
|
||||||
SimpleExoPlayer player =
|
|
||||||
new SimpleExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
|
|
||||||
Player.Listener playerListener = mock(Player.Listener.class);
|
|
||||||
player.addListener(playerListener);
|
|
||||||
AnalyticsListener analyticsListener = mock(AnalyticsListener.class);
|
|
||||||
player.addAnalyticsListener(analyticsListener);
|
|
||||||
|
|
||||||
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setTitle("test").build();
|
|
||||||
player.setPlaylistMetadata(mediaMetadata);
|
|
||||||
|
|
||||||
verify(playerListener).onPlaylistMetadataChanged(mediaMetadata);
|
|
||||||
verify(analyticsListener).onPlaylistMetadataChanged(any(), eq(mediaMetadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void release_triggersAllPendingEventsInAnalyticsListeners() throws Exception {
|
|
||||||
SimpleExoPlayer player =
|
|
||||||
new SimpleExoPlayer.Builder(
|
|
||||||
ApplicationProvider.getApplicationContext(),
|
|
||||||
(handler, videoListener, audioListener, textOutput, metadataOutput) ->
|
|
||||||
new Renderer[] {new FakeVideoRenderer(handler, videoListener)})
|
|
||||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
|
||||||
.build();
|
|
||||||
AnalyticsListener listener = mock(AnalyticsListener.class);
|
|
||||||
player.addAnalyticsListener(listener);
|
|
||||||
// Do something that requires clean-up callbacks like decoder disabling.
|
|
||||||
player.setMediaSource(
|
|
||||||
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
|
|
||||||
player.prepare();
|
|
||||||
player.play();
|
|
||||||
runUntilPlaybackState(player, Player.STATE_READY);
|
|
||||||
|
|
||||||
player.release();
|
|
||||||
ShadowLooper.runMainLooperToNextTask();
|
|
||||||
|
|
||||||
verify(listener).onVideoDisabled(any(), any());
|
|
||||||
verify(listener).onPlayerReleased(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void releaseAfterRendererEvents_triggersPendingVideoEventsInListener() throws Exception {
|
|
||||||
Surface surface = new Surface(new SurfaceTexture(/* texName= */ 0));
|
|
||||||
SimpleExoPlayer player =
|
|
||||||
new SimpleExoPlayer.Builder(
|
|
||||||
ApplicationProvider.getApplicationContext(),
|
|
||||||
(handler, videoListener, audioListener, textOutput, metadataOutput) ->
|
|
||||||
new Renderer[] {new FakeVideoRenderer(handler, videoListener)})
|
|
||||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
|
||||||
.build();
|
|
||||||
Player.Listener listener = mock(Player.Listener.class);
|
|
||||||
player.addListener(listener);
|
|
||||||
player.setMediaSource(
|
|
||||||
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
|
|
||||||
player.setVideoSurface(surface);
|
|
||||||
player.prepare();
|
|
||||||
player.play();
|
|
||||||
runUntilPlaybackState(player, Player.STATE_READY);
|
|
||||||
|
|
||||||
player.release();
|
|
||||||
surface.release();
|
|
||||||
ShadowLooper.runMainLooperToNextTask();
|
|
||||||
|
|
||||||
verify(listener, atLeastOnce()).onEvents(any(), any()); // EventListener
|
|
||||||
verify(listener).onRenderedFirstFrame(); // VideoListener
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void releaseAfterVolumeChanges_triggerPendingVolumeEventInListener() throws Exception {
|
|
||||||
SimpleExoPlayer player =
|
|
||||||
new SimpleExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
|
|
||||||
Player.Listener listener = mock(Player.Listener.class);
|
|
||||||
player.addListener(listener);
|
|
||||||
|
|
||||||
player.setVolume(0F);
|
|
||||||
player.release();
|
|
||||||
ShadowLooper.runMainLooperToNextTask();
|
|
||||||
|
|
||||||
verify(listener).onVolumeChanged(anyFloat());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void releaseAfterVolumeChanges_triggerPendingDeviceVolumeEventsInListener() {
|
|
||||||
SimpleExoPlayer player =
|
|
||||||
new SimpleExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
|
|
||||||
Player.Listener listener = mock(Player.Listener.class);
|
|
||||||
player.addListener(listener);
|
|
||||||
|
|
||||||
int deviceVolume = player.getDeviceVolume();
|
|
||||||
try {
|
|
||||||
player.setDeviceVolume(deviceVolume + 1); // No-op if at max volume.
|
|
||||||
player.setDeviceVolume(deviceVolume - 1); // No-op if at min volume.
|
|
||||||
} finally {
|
|
||||||
player.setDeviceVolume(deviceVolume); // Restore original volume.
|
|
||||||
}
|
|
||||||
|
|
||||||
player.release();
|
|
||||||
ShadowLooper.runMainLooperToNextTask();
|
|
||||||
|
|
||||||
verify(listener, atLeast(2)).onDeviceVolumeChanged(anyInt(), anyBoolean());
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,10 +25,10 @@ import androidx.media3.common.util.Assertions;
|
|||||||
import androidx.media3.common.util.Clock;
|
import androidx.media3.common.util.Clock;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.exoplayer.DefaultLoadControl;
|
import androidx.media3.exoplayer.DefaultLoadControl;
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
import androidx.media3.exoplayer.LoadControl;
|
import androidx.media3.exoplayer.LoadControl;
|
||||||
import androidx.media3.exoplayer.Renderer;
|
import androidx.media3.exoplayer.Renderer;
|
||||||
import androidx.media3.exoplayer.RenderersFactory;
|
import androidx.media3.exoplayer.RenderersFactory;
|
||||||
import androidx.media3.exoplayer.SimpleExoPlayer;
|
|
||||||
import androidx.media3.exoplayer.analytics.DefaultAnalyticsCollector;
|
import androidx.media3.exoplayer.analytics.DefaultAnalyticsCollector;
|
||||||
import androidx.media3.exoplayer.source.MediaSource;
|
import androidx.media3.exoplayer.source.MediaSource;
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
|
||||||
@ -36,8 +36,7 @@ import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
|||||||
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/** A builder of {@link SimpleExoPlayer} instances for testing. */
|
/** A builder of {@link ExoPlayer} instances for testing. */
|
||||||
@SuppressWarnings("deprecation") // Returning deprecated type for backwards compatibility.
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class TestExoPlayerBuilder {
|
public class TestExoPlayerBuilder {
|
||||||
|
|
||||||
@ -275,8 +274,8 @@ public class TestExoPlayerBuilder {
|
|||||||
return seekForwardIncrementMs;
|
return seekForwardIncrementMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builds an {@link SimpleExoPlayer} using the provided values or their defaults. */
|
/** Builds an {@link ExoPlayer} using the provided values or their defaults. */
|
||||||
public SimpleExoPlayer build() {
|
public ExoPlayer build() {
|
||||||
Assertions.checkNotNull(
|
Assertions.checkNotNull(
|
||||||
looper, "TestExoPlayer builder run on a thread without Looper and no Looper specified.");
|
looper, "TestExoPlayer builder run on a thread without Looper and no Looper specified.");
|
||||||
// Do not update renderersFactory and renderers here, otherwise their getters may
|
// Do not update renderersFactory and renderers here, otherwise their getters may
|
||||||
@ -297,8 +296,8 @@ public class TestExoPlayerBuilder {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleExoPlayer.Builder builder =
|
ExoPlayer.Builder builder =
|
||||||
new SimpleExoPlayer.Builder(context, playerRenderersFactory)
|
new ExoPlayer.Builder(context, playerRenderersFactory)
|
||||||
.setTrackSelector(trackSelector)
|
.setTrackSelector(trackSelector)
|
||||||
.setLoadControl(loadControl)
|
.setLoadControl(loadControl)
|
||||||
.setBandwidthMeter(bandwidthMeter)
|
.setBandwidthMeter(bandwidthMeter)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user