/*
* Copyright (c) 2009-2011 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.actions.strategies.links;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.io.IOException;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.Description;
import org.jmock.Expectations;
import org.jmock.States;
import org.jmock.api.Action;
import org.jmock.api.Invocation;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Test fixture for ConnectionFacade.
*/
public class ConnectionFacadeTest
{
/** Test data. */
private static final String URL = "http://www.eurekastreams.org";
/** Test data. */
private static final String ACCOUNT_ID = "jdoe";
/** Used for mocking objects. */
private final JUnit4Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/** Fixture: connection. */
private final HttpURLConnection connection = context.mock(HttpURLConnection.class);
/** SUT. */
private ConnectionFacade sut;
/**
* Setup before each test.
*/
@Before
public void setUp()
{
sut = new ConnectionFacade(new ArrayList<ConnectionFacadeDecorator>());
}
/**
* Test getter and setter for redirectCodes property.
*/
@Test
public void testRedirectCodesProperty()
{
List<Integer> redirectCodes = new ArrayList<Integer>();
sut.setRedirectCodes(redirectCodes);
assertSame(redirectCodes, sut.getRedirectCodes());
}
/**
* Test the getter and setter for the proxyPort property.
*/
@Test
public void testProxyPortProperty()
{
String proxyPort = "1234";
sut.setProxyPort(proxyPort);
assertEquals(proxyPort, sut.getProxyPort());
}
/**
* Test the getter and setter for the proxyHost property.
*/
@Test
public void testProxyHostProperty()
{
String proxyHost = "some.proxy.host";
sut.setProxyHost(proxyHost);
assertEquals(proxyHost, sut.getProxyHost());
}
/**
* Test the connection timeout property.
*/
@Test
public void testConnectionTimeoutProperty()
{
final int connectionTimeout = 834;
sut.setConnectionTimeOut(connectionTimeout);
assertEquals(connectionTimeout, sut.getConnectionTimeOut());
}
/**
* Test the connection timeout property.
*/
@Test
public void testConnectionTimeoutPropertyAtLowerBoundary()
{
final int connectionTimeout = 0;
sut.setConnectionTimeOut(connectionTimeout);
assertEquals(connectionTimeout, sut.getConnectionTimeOut());
}
/**
* Test the connection timeout property.
*/
@Test
public void testConnectionTimeoutPropertyAtMaxBoundary()
{
final int connectionTimeout = 30000;
sut.setConnectionTimeOut(connectionTimeout);
assertEquals(connectionTimeout, sut.getConnectionTimeOut());
}
/**
* Test the connection timeout property.
*/
@Test(expected = InvalidParameterException.class)
public void testConnectionTimeoutPropertyLessThanMinValue()
{
final int connectionTimeout = -1;
sut.setConnectionTimeOut(connectionTimeout);
}
/**
* Test the connection timeout property.
*/
@Test(expected = InvalidParameterException.class)
public void testConnectionTimeoutPropertyMoreThanMaxValue()
{
final int connectionTimeout = 300001;
sut.setConnectionTimeOut(connectionTimeout);
}
/* ---- getFinalUrl tests ---- */
/**
* Common setup for most getFinalUrl tests.
*/
private void setupForGetFinalUrlTests()
{
sut = new ConnectionFacade(new ArrayList<ConnectionFacadeDecorator>())
{
@Override
protected HttpURLConnection getConnection(final String inUrl, final String inAccountId)
throws MalformedURLException
{
return connection;
}
};
// checkstyle rules gone too far
final int rc301 = 301;
final int rc302 = 302;
final int rc303 = 303;
final int rc307 = 307;
sut.setRedirectCodes(Arrays.asList(rc301, rc302, rc303, rc307));
}
/**
* Tests getFinalUrl for connection setup failure.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testGetFinalUrlInvalid() throws IOException
{
sut = new ConnectionFacade(new ArrayList<ConnectionFacadeDecorator>())
{
@Override
protected HttpURLConnection getConnection(final String inUrl, final String inAccountId)
throws MalformedURLException
{
return null;
}
};
assertEquals(URL, sut.getFinalUrl(URL, ACCOUNT_ID));
}
/**
* Tests getFinalUrl.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testGetFinalUrlRedirectHTTP() throws IOException
{
final String newUrl = "http://www.apache.org";
final int rc = 301;
setupForGetFinalUrlTests();
context.checking(new Expectations()
{
{
allowing(connection).getResponseCode();
will(returnValue(rc));
allowing(connection).getHeaderField("Location");
will(returnValue(newUrl));
}
});
assertEquals(newUrl, sut.getFinalUrl(URL, ACCOUNT_ID));
}
/**
* Tests getFinalUrl.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testGetFinalUrlRedirectHTTPS() throws IOException
{
final String newUrl = "https://www.apache.org";
final int rc = 301;
setupForGetFinalUrlTests();
context.checking(new Expectations()
{
{
allowing(connection).getResponseCode();
will(returnValue(rc));
allowing(connection).getHeaderField("Location");
will(returnValue(newUrl));
}
});
assertEquals(URL, sut.getFinalUrl(URL, ACCOUNT_ID));
}
/**
* Tests getFinalUrl.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testGetFinalUrlNoRedirect() throws IOException
{
final int rc = 200;
setupForGetFinalUrlTests();
context.checking(new Expectations()
{
{
allowing(connection).getResponseCode();
will(returnValue(rc));
}
});
assertEquals(URL, sut.getFinalUrl(URL, ACCOUNT_ID));
}
/* ---- File download tests ---- */
/** Test data. */
private static final int EXPECTED_MAX_FILE_SIZE = 20;
/** Test data. */
private static final int MAX_FILE_SIZE = 50;
/** Fixture: httpReader. */
private final Reader httpReader = context.mock(Reader.class);
/**
* Action used to return a value when a stream is read.
*/
private class ReadAction implements Action
{
/** Value to return from read. */
private final String value;
/**
* Constructor.
*
* @param inValue
* Value to return from read.
*/
public ReadAction(final String inValue)
{
value = inValue;
}
/**
* {@inheritDoc}
*/
@Override
public void describeTo(final Description inArg0)
{
}
/**
* {@inheritDoc}
*/
@Override
public Object invoke(final Invocation inInvocation) throws Throwable
{
int targetPos = inInvocation.getParameterCount() > 1 ? (int) (Integer) inInvocation.getParameter(1) : 0;
System.arraycopy(value.toCharArray(), 0, (inInvocation.getParameter(0)), targetPos, value.length());
return value.length();
}
}
/**
* Common setup for download file tests.
*/
private void setupForDownloadFileTests()
{
sut = new ConnectionFacade(new ArrayList<ConnectionFacadeDecorator>())
{
@Override
protected Reader getConnectionReader(final String inUrl, final String inAccountId) throws IOException
{
if (!URL.equals(inUrl) || !ACCOUNT_ID.equals(inAccountId))
{
Assert.fail("getConnectionReader invoked with wrong arguments.");
}
return httpReader;
}
};
sut.setExpectedDownloadFileLimit(EXPECTED_MAX_FILE_SIZE);
sut.setMaximumDownloadFileLimit(MAX_FILE_SIZE);
}
/**
* Tests downloading a file.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testDownloadFileEmpty() throws IOException
{
setupForDownloadFileTests();
final States state = context.states("readStep").startsAs("1");
context.checking(new Expectations()
{
{
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("1"));
then(state.is("2"));
will(returnValue(-1));
oneOf(httpReader).close();
when(state.is("2"));
then(state.is("E"));
}
});
assertEquals("", sut.downloadFile(URL, ACCOUNT_ID));
context.assertIsSatisfied();
}
/**
* Tests downloading a file.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testDownloadFileSmall() throws IOException
{
setupForDownloadFileTests();
final States state = context.states("readStep").startsAs("1");
context.checking(new Expectations()
{
{
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("1"));
then(state.is("2"));
will(new ReadAction("ABCDEFGHIJ"));
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("2"));
then(state.is("3"));
will(new ReadAction("WXYZ"));
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("3"));
then(state.is("4"));
will(returnValue(-1));
oneOf(httpReader).close();
when(state.is("4"));
then(state.is("E"));
}
});
assertEquals("ABCDEFGHIJWXYZ", sut.downloadFile(URL, ACCOUNT_ID));
context.assertIsSatisfied();
}
/**
* Tests downloading a file.
*
* @throws IOException
* Shouldn't.
*/
@Test
public void testDownloadFileLarge() throws IOException
{
setupForDownloadFileTests();
final States state = context.states("readStep").startsAs("1");
context.checking(new Expectations()
{
{
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("1"));
then(state.is("2"));
will(new ReadAction("ABCDEFGHIJ"));
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("2"));
then(state.is("3"));
will(new ReadAction("abcdefghij"));
oneOf(httpReader).read(with(any(char[].class)));
when(state.is("3"));
then(state.is("4"));
will(new ReadAction("MMM"));
oneOf(httpReader).read(with(any(char[].class)));
when(state.is("4"));
then(state.is("5"));
will(new ReadAction("ZZZ"));
oneOf(httpReader).read(with(any(char[].class)));
when(state.is("5"));
then(state.is("6"));
will(returnValue(-1));
oneOf(httpReader).close();
when(state.is("6"));
then(state.is("E"));
}
});
assertEquals("ABCDEFGHIJabcdefghijMMMZZZ", sut.downloadFile(URL, ACCOUNT_ID));
context.assertIsSatisfied();
}
/**
* Tests downloading a file.
*
* @throws IOException
* Shouldn't.
*/
@Test(expected = AssertionError.class)
public void testDownloadFileTooLarge() throws IOException
{
setupForDownloadFileTests();
final States state = context.states("readStep").startsAs("1");
context.checking(new Expectations()
{
{
oneOf(httpReader).read(with(any(char[].class)), with(any(int.class)), with(any(int.class)));
when(state.is("1"));
then(state.is("2"));
will(new ReadAction("ABCDEFGHIJabcdefghij"));
oneOf(httpReader).read(with(any(char[].class)));
when(state.is("2"));
then(state.is("3"));
will(new ReadAction("01234567890123456789"));
oneOf(httpReader).read(with(any(char[].class)));
when(state.is("3"));
then(state.is("4"));
will(new ReadAction("AbCdEfGhIjK"));
}
});
sut.downloadFile(URL, ACCOUNT_ID);
context.assertIsSatisfied();
}
}