Added support for file downloads to HTTP test server, update media player tests
This commit is contained in:
parent
6266f5b298
commit
4c0a8297e1
Binary file not shown.
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue