summaryrefslogtreecommitdiff
path: root/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java
blob: 23c129cb1972be2ad8d060243212dfebd37a8f53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package de.test.antennapod.storage;

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
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.util.playback.PlaybackServiceStarter;
import de.test.antennapod.EspressoTestUtils;
import de.test.antennapod.ui.UITestUtils;
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 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 StubDownloadAlgorithm stubDownloadAlgorithm;

    @Before
    public void setUp() throws Exception {
        context = ApplicationProvider.getApplicationContext();

        stubFeedsServer = new UITestUtils(context);
        stubFeedsServer.setup();

        EspressoTestUtils.clearPreferences();
        EspressoTestUtils.clearDatabase();
        UserPreferences.setAllowMobileStreaming(true);

        // Setup: enable automatic download
        // it is not needed, as the actual automatic download is stubbed.
        stubDownloadAlgorithm = new StubDownloadAlgorithm();
        DBTasks.setDownloadAlgorithm(stubDownloadAlgorithm);
    }

    @After
    public void tearDown() throws Exception {
        DBTasks.setDownloadAlgorithm(new AutomaticDownloadAlgorithm());
        EspressoTestUtils.tryKillPlaybackService();
        stubFeedsServer.tearDown();
    }

    /**
     * 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);

        // 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.getMedia().getId() == stubDownloadAlgorithm.getCurrentlyPlayingAtDownload());
        } catch (ConditionTimeoutException cte) {
            long actual = stubDownloadAlgorithm.getCurrentlyPlayingAtDownload();
            fail("when auto download is triggered, the next episode should be playing: ("
                    + item1.getId() + ", " + item1.getTitle() + ") . "
                    + "Actual playing: (" + actual + ")"
            );
        }
    }

    private void playEpisode(@NonNull FeedItem item) {
        FeedMedia media = item.getMedia();
        new PlaybackServiceStarter(context, media)
                .callEvenIfRunning(true)
                .startWhenPrepared(true)
                .shouldStream(true)
                .start();
        Awaitility.await("episode is playing")
                .atMost(2000, MILLISECONDS)
                .until(() -> item.getMedia().getId() == PlaybackPreferences.getCurrentlyPlayingFeedMediaId());
    }

    private static class StubDownloadAlgorithm extends AutomaticDownloadAlgorithm {
        private long currentlyPlaying = -1;

        @Override
        public Runnable autoDownloadUndownloadedItems(Context context) {
            return () -> {
                if (currentlyPlaying == -1) {
                    currentlyPlaying = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
                } else {
                    throw new AssertionError("Stub automatic download should be invoked once and only once");
                }
            };
        }

        long getCurrentlyPlayingAtDownload() {
            return currentlyPlaying;
        }
    }
}