diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2014-05-18 21:33:50 +0200 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2014-05-18 21:33:50 +0200 |
commit | 4c0a8297e130268b8f8a401d3bc52c801a1bb4f7 (patch) | |
tree | 9f2aca98e3d4c92208ebde51bcbfc0b527454ce9 /src | |
parent | 6266f5b2982d3b91a2f07bd227c31ab1e9cd7af8 (diff) | |
download | AntennaPod-4c0a8297e130268b8f8a401d3bc52c801a1bb4f7.zip |
Added support for file downloads to HTTP test server, update media player tests
Diffstat (limited to 'src')
3 files changed, 146 insertions, 11 deletions
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() { |