summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-05-18 21:33:50 +0200
committerdaniel oeh <daniel.oeh@gmail.com>2014-05-18 21:33:50 +0200
commit4c0a8297e130268b8f8a401d3bc52c801a1bb4f7 (patch)
tree9f2aca98e3d4c92208ebde51bcbfc0b527454ce9
parent6266f5b2982d3b91a2f07bd227c31ab1e9cd7af8 (diff)
downloadAntennaPod-4c0a8297e130268b8f8a401d3bc52c801a1bb4f7.zip
Added support for file downloads to HTTP test server, update media player tests
-rw-r--r--assets/testfile.mp3bin0 -> 20606 bytes
-rw-r--r--src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java2
-rw-r--r--src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java16
-rw-r--r--src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java139
4 files changed, 146 insertions, 11 deletions
diff --git a/assets/testfile.mp3 b/assets/testfile.mp3
new file mode 100644
index 000000000..f15faadf3
--- /dev/null
+++ b/assets/testfile.mp3
Binary files differ
diff --git a/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java b/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
index ceafb2e8e..f4726504e 100644
--- a/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -45,7 +45,7 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
destDir = getInstrumentation().getTargetContext().getExternalFilesDir(DOWNLOAD_DIR);
assertNotNull(destDir);
assertTrue(destDir.exists());
- httpServer = new HTTPBin(HTTPBin.PORT);
+ httpServer = new HTTPBin();
httpServer.start();
}
diff --git a/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index 8a270715f..71747dae8 100644
--- a/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/src/instrumentationTest/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -10,6 +10,7 @@ import de.danoeh.antennapod.service.playback.PlaybackServiceMediaPlayer;
import de.danoeh.antennapod.service.playback.PlayerStatus;
import de.danoeh.antennapod.storage.PodDBAdapter;
import de.danoeh.antennapod.util.playback.Playable;
+import instrumentationTest.de.test.antennapod.util.service.download.HTTPBin;
import junit.framework.AssertionFailedError;
import org.apache.commons.io.IOUtils;
@@ -17,7 +18,6 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
@@ -29,17 +29,20 @@ import java.util.concurrent.TimeUnit;
public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
private static final String TAG = "PlaybackServiceMediaPlayerTest";
- private static final String PLAYABLE_FILE_URL = "http://hpr.dogphilosophy.net/test/mp3.mp3";
- private static final String PLAYABLE_DEST_URL = "psmptestfile.wav";
+ private static final String PLAYABLE_FILE_URL = "http://127.0.0.1:" + HTTPBin.PORT + "/files/0";
+ private static final String PLAYABLE_DEST_URL = "psmptestfile.mp3";
private String PLAYABLE_LOCAL_URL = null;
private static final int LATCH_TIMEOUT_SECONDS = 10;
+ private HTTPBin httpServer;
+
private volatile AssertionFailedError assertionError;
@Override
protected void tearDown() throws Exception {
super.tearDown();
PodDBAdapter.deleteDatabase(getInstrumentation().getTargetContext());
+ httpServer.stop();
}
@Override
@@ -53,6 +56,10 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
adapter.close();
+
+ httpServer = new HTTPBin();
+ httpServer.start();
+
File cacheDir = context.getExternalFilesDir("testFiles");
if (cacheDir == null)
cacheDir = context.getExternalFilesDir("testFiles");
@@ -62,7 +69,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
assertTrue(cacheDir.canWrite());
assertTrue(cacheDir.canRead());
if (!dest.exists()) {
- InputStream i = new URL(PLAYABLE_FILE_URL).openStream();
+ InputStream i = getInstrumentation().getTargetContext().getAssets().open("testfile.mp3");
OutputStream o = new FileOutputStream(new File(cacheDir, PLAYABLE_DEST_URL));
IOUtils.copy(i, o);
o.flush();
@@ -70,6 +77,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
i.close();
}
PLAYABLE_LOCAL_URL = "file://" + dest.getAbsolutePath();
+ assertEquals(0, httpServer.serveFile(dest));
}
private void checkPSMPInfo(PlaybackServiceMediaPlayer.PSMPInfo info) {
diff --git a/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java b/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
index b65ecf2db..272bcda5e 100644
--- a/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
+++ b/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
@@ -3,11 +3,12 @@ package instrumentationTest.de.test.antennapod.util.service.download;
import android.util.Base64;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
import java.io.*;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Random;
+import java.net.URLConnection;
+import java.util.*;
import java.util.zip.GZIPOutputStream;
/**
@@ -29,12 +30,52 @@ public class HTTPBin extends NanoHTTPD {
private static final String MIME_HTML = "text/html";
private static final String MIME_PLAIN = "text/plain";
- public HTTPBin(int port) {
- super(port);
- }
+ private List<File> servedFiles;
public HTTPBin() {
super(PORT);
+ this.servedFiles = new ArrayList<File>();
+ }
+
+ /**
+ * Adds the given file to the server.
+ *
+ * @return The ID of the file or -1 if the file could not be added to the server.
+ */
+ public synchronized int serveFile(File file) {
+ if (file == null) throw new IllegalArgumentException("file = null");
+ if (!file.exists()) {
+ return -1;
+ }
+ for (int i = 0; i < servedFiles.size(); i++) {
+ if (servedFiles.get(i).getAbsolutePath().equals(file.getAbsolutePath())) {
+ return i;
+ }
+ }
+ servedFiles.add(file);
+ return servedFiles.size() - 1;
+ }
+
+ /**
+ * Removes the file with the given ID from the server.
+ *
+ * @return True if a file was removed, false otherwise
+ */
+ public synchronized boolean removeFile(int id) {
+ if (id < 0) throw new IllegalArgumentException("ID < 0");
+ if (id >= servedFiles.size()) {
+ return false;
+ } else {
+ return servedFiles.remove(id) != null;
+ }
+ }
+
+ private synchronized File accessFile(int id) {
+ if (id < 0 || id >= servedFiles.size()) {
+ return null;
+ } else {
+ return servedFiles.get(id);
+ }
}
@Override
@@ -131,11 +172,94 @@ public class HTTPBin extends NanoHTTPD {
e.printStackTrace();
return getInternalError();
}
+ } else if (func.equalsIgnoreCase("files")) {
+ try {
+ int id = Integer.parseInt(param);
+ if (id < 0) {
+ Log.w(TAG, "Invalid ID: " + id);
+ throw new NumberFormatException();
+ }
+ return getFileAccessResponse(id, headers);
+
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ return getInternalError();
+ }
}
return get404Error();
}
+ private synchronized Response getFileAccessResponse(int id, Map<String, String> header) {
+ File file = accessFile(id);
+ if (file == null || !file.exists()) {
+ Log.w(TAG, "File not found: " + id);
+ return get404Error();
+ }
+ InputStream inputStream = null;
+ String contentRange = null;
+ Response.Status status;
+ boolean successful = false;
+ try {
+ inputStream = new FileInputStream(file);
+ if (header.containsKey("range")) {
+ // read range header field
+ final String value = header.get("range");
+ final String[] segments = value.split("=");
+ if (segments.length != 2) {
+ Log.w(TAG, "Invalid segment length: " + Arrays.toString(segments));
+ return getInternalError();
+ }
+ final String type = StringUtils.substringBefore(value, "=");
+ if (!type.equalsIgnoreCase("bytes")) {
+ Log.w(TAG, "Range is not specified in bytes: " + value);
+ return getInternalError();
+ }
+ try {
+ long start = Long.parseLong(StringUtils.substringBefore(segments[1], "-"));
+ if (start >= file.length()) {
+ return getRangeNotSatisfiable();
+ }
+
+ // skip 'start' bytes
+ IOUtils.skipFully(inputStream, start);
+ contentRange = "bytes " + start + (file.length() - 1) + "/" + file.length();
+
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ return getInternalError();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return getInternalError();
+ }
+
+ status = Response.Status.PARTIAL_CONTENT;
+
+ } else {
+ // request did not contain range header field
+ status = Response.Status.OK;
+ }
+ successful = true;
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+
+ return getInternalError();
+ } finally {
+ if (!successful && inputStream != null) {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+
+ Response response = new Response(status, URLConnection.guessContentTypeFromName(file.getAbsolutePath()), inputStream);
+
+ response.addHeader("Accept-Ranges", "bytes");
+ if (contentRange != null) {
+ response.addHeader("Content-Range", contentRange);
+ }
+ response.addHeader("Content-Length", String.valueOf(file.length()));
+ return response;
+ }
+
private Response getGzippedResponse(int size) throws IOException {
try {
Thread.sleep(5000);
@@ -208,7 +332,10 @@ public class HTTPBin extends NanoHTTPD {
private Response getInternalError() {
return new Response(Response.Status.INTERNAL_ERROR, MIME_HTML, "The server encountered an internal error");
+ }
+ private Response getRangeNotSatisfiable() {
+ return new Response(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAIN, "");
}
private Response get404Error() {