Added support for file downloads to HTTP test server, update media player tests

This commit is contained in:
daniel oeh 2014-05-18 21:33:50 +02:00
parent 6266f5b298
commit 4c0a8297e1
4 changed files with 146 additions and 11 deletions

BIN
assets/testfile.mp3 Normal file

Binary file not shown.

View File

@ -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();
}

View File

@ -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) {

View File

@ -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() {