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.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.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -180,7 +182,9 @@ import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowAudioManager;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
/** Unit test for {@link ExoPlayer}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@ -11468,6 +11472,122 @@ public final class ExoPlayerTest {
|
||||
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.
|
||||
|
||||
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
||||
@ -11587,7 +11707,7 @@ public final class ExoPlayerTest {
|
||||
@Override
|
||||
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
super.render(positionUs, elapsedRealtimeUs);
|
||||
if (sleepOnNextRender.compareAndSet(/* expect= */ true, /* update= */ false)) {
|
||||
if (sleepOnNextRender.compareAndSet(/* expectedValue= */ true, /* newValue= */ false)) {
|
||||
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.UnstableApi;
|
||||
import androidx.media3.exoplayer.DefaultLoadControl;
|
||||
import androidx.media3.exoplayer.ExoPlayer;
|
||||
import androidx.media3.exoplayer.LoadControl;
|
||||
import androidx.media3.exoplayer.Renderer;
|
||||
import androidx.media3.exoplayer.RenderersFactory;
|
||||
import androidx.media3.exoplayer.SimpleExoPlayer;
|
||||
import androidx.media3.exoplayer.analytics.DefaultAnalyticsCollector;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
|
||||
@ -36,8 +36,7 @@ import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
||||
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/** A builder of {@link SimpleExoPlayer} instances for testing. */
|
||||
@SuppressWarnings("deprecation") // Returning deprecated type for backwards compatibility.
|
||||
/** A builder of {@link ExoPlayer} instances for testing. */
|
||||
@UnstableApi
|
||||
public class TestExoPlayerBuilder {
|
||||
|
||||
@ -275,8 +274,8 @@ public class TestExoPlayerBuilder {
|
||||
return seekForwardIncrementMs;
|
||||
}
|
||||
|
||||
/** Builds an {@link SimpleExoPlayer} using the provided values or their defaults. */
|
||||
public SimpleExoPlayer build() {
|
||||
/** Builds an {@link ExoPlayer} using the provided values or their defaults. */
|
||||
public ExoPlayer build() {
|
||||
Assertions.checkNotNull(
|
||||
looper, "TestExoPlayer builder run on a thread without Looper and no Looper specified.");
|
||||
// Do not update renderersFactory and renderers here, otherwise their getters may
|
||||
@ -297,8 +296,8 @@ public class TestExoPlayerBuilder {
|
||||
};
|
||||
}
|
||||
|
||||
SimpleExoPlayer.Builder builder =
|
||||
new SimpleExoPlayer.Builder(context, playerRenderersFactory)
|
||||
ExoPlayer.Builder builder =
|
||||
new ExoPlayer.Builder(context, playerRenderersFactory)
|
||||
.setTrackSelector(trackSelector)
|
||||
.setLoadControl(loadControl)
|
||||
.setBandwidthMeter(bandwidthMeter)
|
||||
|
Loading…
x
Reference in New Issue
Block a user