-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2714 from orionlee/enqueue_keep_inprogress_front_…
…2652_respect_download_start_order_2448 Enqueue fixes: keep inprogress front, respect download start order
- Loading branch information
Showing
21 changed files
with
943 additions
and
101 deletions.
There are no files selected for viewing
168 changes: 168 additions & 0 deletions
168
app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package de.test.antennapod.storage; | ||
|
||
import android.content.Context; | ||
import android.content.Intent; | ||
|
||
import androidx.annotation.NonNull; | ||
import androidx.annotation.Nullable; | ||
import androidx.test.core.app.ApplicationProvider; | ||
|
||
import org.awaitility.Awaitility; | ||
import org.awaitility.core.ConditionTimeoutException; | ||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import java.util.List; | ||
|
||
import de.danoeh.antennapod.core.ClientConfig; | ||
import de.danoeh.antennapod.core.DBTasksCallbacks; | ||
import de.danoeh.antennapod.core.feed.FeedItem; | ||
import de.danoeh.antennapod.core.feed.FeedMedia; | ||
import de.danoeh.antennapod.core.preferences.UserPreferences; | ||
import de.danoeh.antennapod.core.service.playback.PlaybackService; | ||
import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm; | ||
import de.danoeh.antennapod.core.storage.DBReader; | ||
import de.danoeh.antennapod.core.storage.DBTasks; | ||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; | ||
import de.danoeh.antennapod.core.storage.PodDBAdapter; | ||
import de.danoeh.antennapod.core.util.playback.Playable; | ||
import de.test.antennapod.ui.UITestUtils; | ||
|
||
import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||
import static org.junit.Assert.assertTrue; | ||
import static org.junit.Assert.fail; | ||
|
||
public class AutoDownloadTest { | ||
|
||
private Context context; | ||
private UITestUtils stubFeedsServer; | ||
|
||
private DBTasksCallbacks dbTasksCallbacksOrig; | ||
|
||
@Before | ||
public void setUp() throws Exception { | ||
context = ApplicationProvider.getApplicationContext(); | ||
|
||
stubFeedsServer = new UITestUtils(context);; | ||
stubFeedsServer.setup(); | ||
|
||
dbTasksCallbacksOrig = ClientConfig.dbTasksCallbacks; | ||
|
||
// create new database | ||
PodDBAdapter.init(context); | ||
PodDBAdapter.deleteDatabase(); | ||
PodDBAdapter adapter = PodDBAdapter.getInstance(); | ||
adapter.open(); | ||
adapter.close(); | ||
} | ||
|
||
@After | ||
public void tearDown() throws Exception { | ||
stubFeedsServer.tearDown(); | ||
|
||
context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); | ||
Awaitility.await().until(() -> !PlaybackService.isRunning); | ||
|
||
ClientConfig.dbTasksCallbacks = dbTasksCallbacksOrig; | ||
} | ||
|
||
/** | ||
* A cross-functional test, ensuring playback's behavior works with Auto Download in boundary condition. | ||
* | ||
* Scenario: | ||
* - For setting enqueue location AFTER_CURRENTLY_PLAYING | ||
* - when playback of an episode is complete and the app advances to the next episode (continuous playback on) | ||
* - when automatic download kicks in, | ||
* - ensure the next episode is the current playing one, needed for AFTER_CURRENTLY_PLAYING enqueue location. | ||
*/ | ||
@Test | ||
public void downloadsEnqueuedToAfterCurrent_CurrentAdvancedToNextOnPlaybackComplete() throws Exception { | ||
UserPreferences.setFollowQueue(true); // continuous playback | ||
|
||
// Setup: feeds and queue | ||
// downloads 3 of them, leave some in new state (auto-downloadable) | ||
stubFeedsServer.addLocalFeedData(false); | ||
List<FeedItem> queue = DBReader.getQueue(); | ||
assertTrue(queue.size() > 1); | ||
FeedItem item0 = queue.get(0); | ||
FeedItem item1 = queue.get(1); | ||
|
||
// Setup: enable automatic download | ||
// it is not needed, as the actual automatic download is stubbed. | ||
StubDownloadAlgorithm stubDownloadAlgorithm = new StubDownloadAlgorithm(); | ||
useDownloadAlgorithm(stubDownloadAlgorithm); | ||
|
||
// Actual test | ||
// Play the first one in the queue | ||
playEpisode(item0); | ||
|
||
try { | ||
// when playback is complete, advances to the next one, and auto download kicks in, | ||
// ensure that currently playing has been advanced to the next one by this point. | ||
Awaitility.await("advanced to the next episode") | ||
.atMost(6000, MILLISECONDS) // the test mp3 media is 3-second long. twice should be enough | ||
.until(() -> item1.equals(stubDownloadAlgorithm.getCurrentlyPlayingAtDownload())); | ||
} catch (ConditionTimeoutException cte) { | ||
FeedItem actual = stubDownloadAlgorithm.getCurrentlyPlayingAtDownload(); | ||
fail("when auto download is triggered, the next episode should be playing: (" | ||
+ item1.getId() + ", " + item1.getTitle() + ") . " | ||
+ "Actual playing: (" | ||
+ (actual == null ? "" : actual.getId() + ", " + actual.getTitle()) + ")" | ||
); | ||
} | ||
|
||
} | ||
|
||
private void playEpisode(@NonNull FeedItem item) { | ||
FeedMedia media = item.getMedia(); | ||
DBTasks.playMedia(context, media, false, true, true); | ||
Awaitility.await("episode is playing") | ||
.atMost(1000, MILLISECONDS) | ||
.until(() -> item.equals(getCurrentlyPlaying())); | ||
} | ||
|
||
private FeedItem getCurrentlyPlaying() { | ||
Playable playable = Playable.PlayableUtils.createInstanceFromPreferences(context); | ||
if (playable == null) { | ||
return null; | ||
} | ||
return ((FeedMedia)playable).getItem(); | ||
} | ||
|
||
private void useDownloadAlgorithm(final AutomaticDownloadAlgorithm downloadAlgorithm) { | ||
DBTasksCallbacks dbTasksCallbacksStub = new DBTasksCallbacks() { | ||
@Override | ||
public AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm() { | ||
return downloadAlgorithm; | ||
} | ||
|
||
@Override | ||
public EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm() { | ||
return dbTasksCallbacksOrig.getEpisodeCacheCleanupAlgorithm(); | ||
} | ||
}; | ||
ClientConfig.dbTasksCallbacks = dbTasksCallbacksStub; | ||
} | ||
|
||
private class StubDownloadAlgorithm implements AutomaticDownloadAlgorithm { | ||
@Nullable | ||
private FeedItem currentlyPlaying; | ||
|
||
@Override | ||
public Runnable autoDownloadUndownloadedItems(Context context) { | ||
return () -> { | ||
if (currentlyPlaying == null) { | ||
currentlyPlaying = getCurrentlyPlaying(); | ||
} else { | ||
throw new AssertionError("Stub automatic download should be invoked once and only once"); | ||
} | ||
}; | ||
} | ||
|
||
@Nullable | ||
FeedItem getCurrentlyPlayingAtDownload() { | ||
return currentlyPlaying; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.