Merge pull request #3477 from orionlee/test_download_service_event_posting
Test download service event posting
This commit is contained in:
commit
8f5ff42f6a
|
@ -0,0 +1,52 @@
|
||||||
|
package de.danoeh.antennapod.core.service.download;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.util.Consumer;
|
||||||
|
|
||||||
|
public class StubDownloader extends Downloader {
|
||||||
|
|
||||||
|
private final long downloadTime;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Consumer<DownloadStatus> onDownloadComplete;
|
||||||
|
|
||||||
|
public StubDownloader(@NonNull DownloadRequest request, long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) {
|
||||||
|
super(request);
|
||||||
|
this.downloadTime = downloadTime;
|
||||||
|
this.onDownloadComplete = onDownloadComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void download() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(downloadTime);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
onDownloadComplete.accept(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DownloadRequest getDownloadRequest() {
|
||||||
|
return super.getDownloadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DownloadStatus getResult() {
|
||||||
|
return super.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
return super.isFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
super.cancel();
|
||||||
|
result.setCancelled();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package de.test.antennapod.service.download;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.awaitility.Awaitility;
|
||||||
|
import org.awaitility.core.ConditionTimeoutException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.feed.Feed;
|
||||||
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
|
import de.danoeh.antennapod.core.service.download.DownloadRequest;
|
||||||
|
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||||
|
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||||
|
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||||
|
import de.danoeh.antennapod.core.service.download.StubDownloader;
|
||||||
|
import de.danoeh.antennapod.core.storage.DBReader;
|
||||||
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
|
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||||
|
import de.danoeh.antennapod.core.util.Consumer;
|
||||||
|
|
||||||
|
import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see HttpDownloaderTest for the test of actual download (and saving the file)
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class DownloadServiceTest {
|
||||||
|
|
||||||
|
private CountDownLatch latch = null;
|
||||||
|
private Feed testFeed = null;
|
||||||
|
private FeedMedia testMedia11 = null;
|
||||||
|
|
||||||
|
private DownloadService.DownloaderFactory origFactory = null;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
origFactory = DownloadService.getDownloaderFactory();
|
||||||
|
testFeed = setUpTestFeeds();
|
||||||
|
testMedia11 = testFeed.getItemAtIndex(0).getMedia();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Feed setUpTestFeeds() throws Exception {
|
||||||
|
Feed feed = new Feed("url", null, "Test Feed title 1");
|
||||||
|
List<FeedItem> items = new ArrayList<>();
|
||||||
|
feed.setItems(items);
|
||||||
|
FeedItem item1 = new FeedItem(0, "Item 1-1", "Item 1-1", "url", new Date(), FeedItem.NEW, feed);
|
||||||
|
items.add(item1);
|
||||||
|
FeedMedia media1 = new FeedMedia(0, item1, 123, 1, 1, "audio/mp3", null, "http://example.com/episode.mp3", false, null, 0, 0);
|
||||||
|
item1.setMedia(media1);
|
||||||
|
|
||||||
|
DBWriter.setFeedItem(item1).get();
|
||||||
|
return feed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
DownloadService.setDownloaderFactory(origFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEventsGeneratedCaseMediaDownloadSuccess() throws Exception {
|
||||||
|
// create a stub download that returns successful
|
||||||
|
//
|
||||||
|
// OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents
|
||||||
|
// are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds)
|
||||||
|
// to do so
|
||||||
|
DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> {
|
||||||
|
downloadStatus.setSuccessful();
|
||||||
|
}));
|
||||||
|
|
||||||
|
withFeedItemEventListener(feedItemEventListener -> {
|
||||||
|
try {
|
||||||
|
assertEquals(0, feedItemEventListener.getEvents().size());
|
||||||
|
assertFalse("The media in test should not yet been downloaded",
|
||||||
|
DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
|
||||||
|
|
||||||
|
DownloadRequester.getInstance().downloadMedia(InstrumentationRegistry.getTargetContext(),
|
||||||
|
testMedia11);
|
||||||
|
Awaitility.await()
|
||||||
|
.atMost(1000, TimeUnit.MILLISECONDS)
|
||||||
|
.until(() -> feedItemEventListener.getEvents().size() > 0);
|
||||||
|
assertTrue("After media download has completed, FeedMedia object in db should indicate so.",
|
||||||
|
DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
|
||||||
|
} catch (ConditionTimeoutException cte) {
|
||||||
|
fail("The expected FeedItemEvent (for media download complete) has not been posted. "
|
||||||
|
+ cte.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StubDownloaderFactory implements DownloadService.DownloaderFactory {
|
||||||
|
private final long downloadTime;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Consumer<DownloadStatus> onDownloadComplete;
|
||||||
|
|
||||||
|
StubDownloaderFactory(long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) {
|
||||||
|
this.downloadTime = downloadTime;
|
||||||
|
this.onDownloadComplete = onDownloadComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Downloader create(@NonNull DownloadRequest request) {
|
||||||
|
return new StubDownloader(request, downloadTime, onDownloadComplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import android.support.test.filters.LargeTest;
|
||||||
|
|
||||||
import org.awaitility.Awaitility;
|
import org.awaitility.Awaitility;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -18,7 +17,6 @@ import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
|
||||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||||
import de.danoeh.antennapod.core.feed.Feed;
|
import de.danoeh.antennapod.core.feed.Feed;
|
||||||
|
@ -29,8 +27,8 @@ import de.danoeh.antennapod.core.storage.DBReader;
|
||||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
|
|
||||||
|
import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -168,35 +166,6 @@ public class PlaybackServiceTaskManagerTest {
|
||||||
pstm.shutdown();
|
pstm.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an listener subscribing to {@link FeedItemEvent} that the callers can use
|
|
||||||
*
|
|
||||||
* Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown.
|
|
||||||
*/
|
|
||||||
private static void withFeedItemEventListener(Consumer<FeedItemEventListener> consumer) throws Exception {
|
|
||||||
FeedItemEventListener feedItemEventListener = new FeedItemEventListener();
|
|
||||||
try {
|
|
||||||
EventBus.getDefault().register(feedItemEventListener);
|
|
||||||
consumer.accept(feedItemEventListener);
|
|
||||||
} finally {
|
|
||||||
EventBus.getDefault().unregister(feedItemEventListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FeedItemEventListener {
|
|
||||||
|
|
||||||
private final List<FeedItemEvent> events = new ArrayList<>();
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onEvent(FeedItemEvent event) {
|
|
||||||
events.add(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<? extends FeedItemEvent> getEvents() {
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartPositionSaver() throws InterruptedException {
|
public void testStartPositionSaver() throws InterruptedException {
|
||||||
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package de.test.antennapod.util.event;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test helpers to listen {@link FeedItemEvent} and handle them accordingly
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FeedItemEventListener {
|
||||||
|
private final List<FeedItemEvent> events = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an listener subscribing to {@link FeedItemEvent} that the callers can use
|
||||||
|
*
|
||||||
|
* Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown.
|
||||||
|
*/
|
||||||
|
public static void withFeedItemEventListener(@NonNull Consumer<FeedItemEventListener> consumer)
|
||||||
|
throws Exception {
|
||||||
|
FeedItemEventListener feedItemEventListener = new FeedItemEventListener();
|
||||||
|
try {
|
||||||
|
EventBus.getDefault().register(feedItemEventListener);
|
||||||
|
consumer.accept(feedItemEventListener);
|
||||||
|
} finally {
|
||||||
|
EventBus.getDefault().unregister(feedItemEventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onEvent(FeedItemEvent event) {
|
||||||
|
events.add(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<? extends FeedItemEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -434,13 +435,41 @@ public class DownloadService extends Service {
|
||||||
queryDownloads();
|
queryDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Downloader getDownloader(DownloadRequest request) {
|
@VisibleForTesting
|
||||||
|
public interface DownloaderFactory {
|
||||||
|
@Nullable
|
||||||
|
Downloader create(@NonNull DownloadRequest request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DefaultDownloaderFactory implements DownloaderFactory {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Downloader create(@NonNull DownloadRequest request) {
|
||||||
if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) {
|
if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) {
|
||||||
Log.e(TAG, "Could not find appropriate downloader for " + request.getSource());
|
Log.e(TAG, "Could not find appropriate downloader for " + request.getSource());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new HttpDownloader(request);
|
return new HttpDownloader(request);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloaderFactory downloaderFactory = new DefaultDownloaderFactory();
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static DownloaderFactory getDownloaderFactory() {
|
||||||
|
return downloaderFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public scope rather than package private,
|
||||||
|
// because androidTest put classes in the non-standard de.test.antennapod hierarchy
|
||||||
|
@VisibleForTesting
|
||||||
|
public static void setDownloaderFactory(DownloaderFactory downloaderFactory) {
|
||||||
|
DownloadService.downloaderFactory = downloaderFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Downloader getDownloader(@NonNull DownloadRequest request) {
|
||||||
|
return downloaderFactory.create(request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove download from the DownloadRequester list and from the
|
* Remove download from the DownloadRequester list and from the
|
||||||
|
|
Loading…
Reference in New Issue