/******************************************************************************* * 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; } }; } }