/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.commons.tests;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import junit.framework.TestCase;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadManager;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadManager.DownloadService;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadableItem;
import org.springsource.ide.eclipse.commons.frameworks.core.util.IOUtil;
public class DownloadManagerTests extends TestCase {
public class TestContent {
public final boolean isError;
public final String data;
public TestContent(boolean isError, String data) {
this.isError = isError;
this.data = data;
}
@Override
public String toString() {
if (isError) {
return "Error("+data+")";
} else {
return data;
}
}
}
/**
* A test DownloadRequesto it 'accepts' downloaded data when it is equal to
* the expected test data and throws an Error otherwise.
*/
public class DownloadAcceptor implements DownloadManager.DownloadRequestor {
private final String expected;
public String data = null; // Set when data read successfully.
public DownloadAcceptor(String expect) {
this.expected = expect;
}
public void exec(File downloadedFile) throws Exception {
String data = getContents(downloadedFile);
if (data.equals(expected)) {
this.data = data;
}
else {
throw new Error("Bad data: " + data);
}
}
private String getContents(File downloadedFile) throws IOException {
FileInputStream input = new FileInputStream(downloadedFile);
ByteArrayOutputStream data = new ByteArrayOutputStream();
IOUtil.pipe(input, data);
return data.toString("utf8");
}
}
/**
* A DownloadService who's behavior for specific urls can be 'programmed'.
*/
public class TestDownloadService implements DownloadService {
private final Map<String, LinkedList<TestContent>> responses = new HashMap<String, LinkedList<TestContent>>();
public int fetchCount = 0;
public void fetch(URL url, OutputStream writeTo) throws IOException {
fetchCount++;
LinkedList<TestContent> rs = responses.get(url.toString());
if (rs == null || rs.isEmpty()) {
throw new IOException("Not found: " + url);
}
TestContent r = rs.removeFirst();
rs.addLast(r);
if (r.isError) {
throw new IOException(r.data);
} else {
writeTo.write(r.data.getBytes("utf8"));
}
}
/**
* Make this downloadservice return given TestContent for a given url.
* If more then one 'TestContent' element is provided the service will
* cycle through them on each download attempt. For example if test content
* is 'a', 'b', 'c' then the first download attempt will return 'a', the second
* 'b', the third 'c' the fourth 'a' again and so on.
*/
public void at(String url, TestContent... content) {
assertTrue(content.length>0);
responses.put(url, new LinkedList<TestContent>(Arrays.asList(content)));
}
}
private DownloadManager downloader;
public void testSimple() throws Exception {
TestDownloadService service = new TestDownloadService();
service.at("http://foo", content("Content for http://foo"));
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
File cacheDir = downloader.getCacheDir();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Content for http://foo");
downloader.doWithDownload(item("foo"), acceptor);
assertEquals("Content for http://foo", acceptor.data);
}
finally {
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
assertEquals(1, service.fetchCount);
}
}
public void testSecondFetchFromCache() throws Exception {
TestDownloadService service = new TestDownloadService();
service.at("http://foo", content("Content for http://foo"));
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
File cacheDir = downloader.getCacheDir();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Content for http://foo");
downloader.doWithDownload(item("foo"), acceptor);
assertEquals("Content for http://foo", acceptor.data);
downloader.doWithDownload(item("foo"), acceptor);
}
finally {
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
//Twice using same data, but only one fetch!
assertEquals(1, service.fetchCount);
}
}
/**
* Check that downloads are retried when download fails with an error.
*/
public void testRetryOnError() throws Exception {
TestDownloadService service = new TestDownloadService();
service.at("http://foo", error("Foo"), error("Foo"), content("Foo"));
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
File cacheDir = downloader.getCacheDir();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Foo");
downloader.doWithDownload(item("foo"), acceptor);
assertEquals("Foo", acceptor.data);
}
finally {
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
//Check fetch count. 2 failed attempts + 1 succesful = 3
assertEquals(3, service.fetchCount);
}
}
/**
* Check that downloads are retried when download succeeds but data is
* 'corrupted'.
*/
public void testRetryOnCorruptedData() throws Exception {
TestDownloadService service = new TestDownloadService();
service.at("http://foo", content("CORRUPTED"), content("GARBAGE"), content("Foo"));
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
File cacheDir = downloader.getCacheDir();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Foo");
downloader.doWithDownload(item("foo"), acceptor);
assertEquals("Foo", acceptor.data);
} finally {
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
//Check fetch count. 2 failed attempts + 1 succesfull = 3
assertEquals(3, service.fetchCount);
}
}
/**
* Check that setting tries limits the number of tries as expected.
*/
public void testRetryCountWithError() throws Exception {
TestDownloadService service = new TestDownloadService();
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
downloader.setTries(3);
File cacheDir = downloader.getCacheDir();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Foo");
downloader.doWithDownload(item("foo"), acceptor);
fail("Download should have failed");
} catch (IOException e) {
assertEquals("Not found: http://foo", e.getMessage());
} finally {
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
//Check fetch count. 2 failed attempts = 1 try and 2 retries
assertEquals(3, service.fetchCount);
}
}
public void testRetryInterval() throws Exception {
TestDownloadService service = new TestDownloadService();
downloader = new DownloadManager(service, null);
downloader.allowUIThread(true);
downloader.setTries(3);
downloader.setRetryInterval(1000);
File cacheDir = downloader.getCacheDir();
long startTime = System.currentTimeMillis();
try {
DownloadAcceptor acceptor = new DownloadAcceptor("Foo");
downloader.doWithDownload(item("foo"), acceptor);
fail("Download should have failed");
} catch (IOException e) {
assertEquals("Not found: http://foo", e.getMessage());
} finally {
long duration = System.currentTimeMillis() - startTime;
//Should expect duration of around 2000 ms as there are 2 retries (and 1 try).
assertTrue("Duration:"+duration, duration>1500);
assertTrue("Duration:"+duration, duration<2500);
downloader.dispose();
// when cachedir was generated by DownloadManager it should be
// deleted on dispose.
assertFalse(cacheDir.exists());
//Check fetch count. 2 failed attempts = 1 try and 2 retries
assertEquals(3, service.fetchCount);
}
}
public TestContent content(String string) {
return new TestContent(false, string);
}
public TestContent error(String msg) {
return new TestContent(true, msg);
}
private DownloadableItem item(final String name) throws MalformedURLException {
return new DownloadableItem(new URL("http://" + name), downloader) {
@Override
protected String getFileName() {
return name;
}
};
}
}