diff options
author | orionlee <orionlee@yahoo.com> | 2019-10-29 15:59:22 -0700 |
---|---|---|
committer | orionlee <orionlee@yahoo.com> | 2019-11-05 12:34:11 -0800 |
commit | 52f6a121f1bc0a1561eef3541dea5226b1c15edf (patch) | |
tree | fcaef08b1c7d0e79b106c14abf245d1bec25fe59 | |
parent | e233398753d9b2a131d51d6ddf44c06d9e42a05e (diff) | |
download | AntennaPod-52f6a121f1bc0a1561eef3541dea5226b1c15edf.zip |
AFTER_CURRENTLY_PLAYING enqueue location option - test boundary condition handling
-rw-r--r-- | app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java | 168 | ||||
-rw-r--r-- | build.gradle | 2 | ||||
-rw-r--r-- | core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java | 8 |
3 files changed, 177 insertions, 1 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java new file mode 100644 index 000000000..c6beb2d42 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java @@ -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; + } + } +} diff --git a/build.gradle b/build.gradle index 8ac4eda94..73eab1704 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ project.ext { workManagerVersion = "1.0.1" espressoVersion = "3.2.0" - awaitilityVersion = "3.1.2" + awaitilityVersion = "3.1.6" commonsioVersion = "2.5" commonslangVersion = "3.6" commonstextVersion = "1.3" diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index 8e7cc1bec..ff2a2e1ca 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -339,6 +339,14 @@ public class UserPreferences { return prefs.getBoolean(PREF_FOLLOW_QUEUE, true); } + /** + * Set to true to enable Continuous Playback + */ + @VisibleForTesting + public static void setFollowQueue(boolean value) { + prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).apply(); + } + public static boolean shouldSkipKeepEpisode() { return prefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true); } public static boolean shouldFavoriteKeepEpisode() { |