Fix flaky ExoPlayerTest tests.

Some tests were flaky because of the PlayUntilPosition action which called
player.setPlayWhenReady from the wrong thread. Also fixed some other misc
flakiness.

ExoPlayerTest seems to be non-flaky now (tested with 10000 runs).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=209743076
This commit is contained in:
tonihei 2018-08-22 03:55:24 -07:00 committed by Oliver Woodman
parent 8927993b03
commit bf43cca302
2 changed files with 30 additions and 22 deletions

View file

@ -29,7 +29,6 @@ import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
@ -1290,12 +1289,12 @@ public final class ExoPlayerTest {
@Test
public void testPlaybackErrorDuringSourceInfoRefreshWithShuffleModeEnabledUsesCorrectFirstPeriod()
throws Exception {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
FakeMediaSource mediaSource = new FakeMediaSource(/* timeline= */ null, /* manifest= */ null);
FakeMediaSource mediaSource =
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), /* manifest= */ null);
ConcatenatingMediaSource concatenatingMediaSource =
new ConcatenatingMediaSource(
/* isAtomic= */ false, new FakeShuffleOrder(0), mediaSource, mediaSource);
AtomicInteger windowIndexAfterReprepare = new AtomicInteger();
AtomicInteger windowIndexAfterError = new AtomicInteger();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testPlaybackErrorDuringSourceInfoRefreshUsesCorrectFirstPeriod")
.setShuffleModeEnabled(true)
@ -1304,17 +1303,12 @@ public final class ExoPlayerTest {
// is still being prepared. The error will be thrown while the player handles the new
// source info.
.seek(/* windowIndex= */ 100, /* positionMs= */ 0)
.executeRunnable(() -> mediaSource.setNewSourceInfo(timeline, /* newManifest= */ null))
.waitForPlaybackState(Player.STATE_IDLE)
// Re-prepare to play the source in its default shuffled order.
.prepareSource(
concatenatingMediaSource, /* resetPosition= */ false, /* resetState= */ false)
.waitForTimelineChanged(null)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
windowIndexAfterReprepare.set(player.getCurrentWindowIndex());
windowIndexAfterError.set(player.getCurrentWindowIndex());
}
})
.build();
@ -1330,7 +1324,7 @@ public final class ExoPlayerTest {
// Expected exception.
assertThat(e.getUnexpectedException()).isInstanceOf(IllegalSeekPositionException.class);
}
assertThat(windowIndexAfterReprepare.get()).isEqualTo(1);
assertThat(windowIndexAfterError.get()).isEqualTo(1);
}
@Test
@ -2253,21 +2247,20 @@ public final class ExoPlayerTest {
@Test
public void testUpdateTrackSelectorThenSeekToUnpreparedPeriod_returnsEmptyTrackGroups()
throws Exception {
Timeline fakeTimeline = new FakeTimeline(/* windowCount= */ 1);
// Use unset duration to prevent pre-loading of the second window.
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ C.TIME_UNSET));
MediaSource[] fakeMediaSources = {
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
new FakeMediaSource(fakeTimeline, null, Builder.AUDIO_FORMAT)
};
MediaSource mediaSource =
new ConcatenatingMediaSource(
/* isAtomic= */ false,
/* useLazyPreparation= */ true,
new ShuffleOrder.DefaultShuffleOrder(0),
fakeMediaSources);
MediaSource mediaSource = new ConcatenatingMediaSource(fakeMediaSources);
FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT);
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testSendMessages")
new ActionSchedule.Builder("testUpdateTrackSelectorThenSeekToUnpreparedPeriod")
.pause()
.waitForPlaybackState(Player.STATE_READY)
.seek(/* windowIndex= */ 1, /* positionMs= */ 0)

View file

@ -34,6 +34,7 @@ import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.HandlerWrapper;
/**
@ -503,10 +504,24 @@ public abstract class Action {
final Surface surface,
final HandlerWrapper handler,
final ActionNode nextAction) {
// Schedule one message on the playback thread to pause the player immediately.
Handler testThreadHandler = new Handler();
// Schedule a message on the playback thread to ensure the player is paused immediately.
player
.createMessage(
(messageType, payload) -> player.setPlayWhenReady(/* playWhenReady= */ false))
(messageType, payload) -> {
// Block playback thread until pause command has been sent from test thread.
ConditionVariable blockPlaybackThreadCondition = new ConditionVariable();
testThreadHandler.post(
() -> {
player.setPlayWhenReady(/* playWhenReady= */ false);
blockPlaybackThreadCondition.open();
});
try {
blockPlaybackThreadCondition.block();
} catch (InterruptedException e) {
// Ignore.
}
})
.setPosition(windowIndex, positionMs)
.send();
// Schedule another message on this test thread to continue action schedule.
@ -515,7 +530,7 @@ public abstract class Action {
(messageType, payload) ->
nextAction.schedule(player, trackSelector, surface, handler))
.setPosition(windowIndex, positionMs)
.setHandler(new Handler())
.setHandler(testThreadHandler)
.send();
player.setPlayWhenReady(true);
}