package com.prasanna.android.http; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.ProtocolVersion; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.runners.MockitoJUnitRunner; import android.graphics.Bitmap; import com.prasanna.android.stacknetwork.matchers.ClientExceptionMatcher; import com.prasanna.android.stacknetwork.matchers.ServerExceptionMatcher; import com.prasanna.android.stacknetwork.service.AbstractBaseServiceHelper; import com.prasanna.android.stacknetwork.utils.JSONObjectWrapper; import com.prasanna.android.stacknetwork.utils.StackUri; import com.prasanna.android.stacknetwork.utils.StackUri.QueryParamDefaultValues; @RunWith(MockitoJUnitRunner.class) public class SecureHttpHelperTest { private static final String SCHEME = "https"; private static final String HOST = "www.example.com"; private static final String PATH = "/v1/path"; @Mock private HttpGzipResponseInterceptor httpGzipResponseInterceptor; @Mock private HttpClient httpClient; @Mock private HttpPost httpPost; @Mock private HttpGet httpGet; @Mock private HttpResponse httpResponse; @Mock private HttpEntity httpEntity; @Rule public ExpectedException expectedException = ExpectedException.none(); private SecureHttpHelperStub secureHttpHelper; private class SecureHttpHelperStub extends SecureHttpHelper { @Override protected HttpClient createSecureHttpClient() { return httpClient; } @Override protected HttpGet getHttpGetObject(String absoluteUrl) { mockGetUri(httpGet, absoluteUrl); return httpGet; } @Override protected HttpPost getHttpPostObject(String absoluteUrl) { mockGetUri(httpPost, absoluteUrl); return httpPost; } @Override protected Bitmap getBitmap(HttpResponse response) throws IOException { return null; } protected String buildUri(String host, String path, Map<String, String> queryParams) { assertEquals(HOST, host); assertEquals(PATH, path); assertEquals(getQueryParams(), queryParams); try { URIBuilder uriBuilder = new URIBuilder().setScheme("https").setHost("www.example.com").setPath("/v1/path"); for (String key : queryParams.keySet()) uriBuilder.addParameter(key, queryParams.get(key)); return uriBuilder.build().toASCIIString(); } catch (URISyntaxException e) { fail(e.getMessage()); } return null; } private void mockGetUri(HttpRequestBase httpRequestBase, String absoluteUrl) { try { when(httpRequestBase.getURI()).thenReturn(new URI(absoluteUrl)); } catch (URISyntaxException e) { fail(e.getMessage()); } } } private Map<String, String> getQueryParams() { Map<String, String> queryParams = new HashMap<String, String>(); queryParams.put(StackUri.QueryParams.PAGE, "1"); queryParams.put(StackUri.QueryParams.CLIENT_ID, QueryParamDefaultValues.CLIENT_ID); return queryParams; } private Map<String, String> getRequestHeaders() { Map<String, String> requestHeaders = new HashMap<String, String>(); requestHeaders.put(HttpHeaderParams.CONTENT_TYPE, HttpContentTypes.APPLICATION_FROM_URL_ENCODED); requestHeaders.put(HttpHeaderParams.ACCEPT, HttpContentTypes.APPLICATION_JSON); return requestHeaders; } private <T extends HttpRequestBase> void verifyExecute(Class<T> argClass) throws IOException, ClientProtocolException { ArgumentCaptor<T> httpGetArgCaptor = ArgumentCaptor.forClass(argClass); verify(httpClient, times(1)).execute(httpGetArgCaptor.capture()); T value = httpGetArgCaptor.getValue(); assertNotNull(value); URI uri = value.getURI(); assertNotNull(uri); assertEquals(SCHEME, uri.getScheme()); assertEquals(HOST, uri.getHost()); assertEquals(PATH, uri.getPath()); assertEquals(getExpectedQuery(), uri.getQuery()); } private String getExpectedQuery() { URIBuilder uriBuilder = new URIBuilder(); Map<String, String> queryParams = getQueryParams(); for (String key : queryParams.keySet()) uriBuilder.setParameter(key, queryParams.get(key)); return uriBuilder.toString().substring(1); } private StatusLine getStatusLine(final int statusCode, final String reasonPhrase) { return new StatusLine() { @Override public int getStatusCode() { return statusCode; } @Override public String getReasonPhrase() { return reasonPhrase; } @Override public ProtocolVersion getProtocolVersion() { return new ProtocolVersion(SCHEME, 1, 1); } }; } @Before public void setup() { MockitoAnnotations.initMocks(SecureHttpHelperTest.class); secureHttpHelper = new SecureHttpHelperStub(); } @Test public void executeHttpGet() throws ClientProtocolException, IOException { when(httpClient.execute(httpGet)).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(getStatusLine(HttpStatus.SC_OK, "OK")); when(httpResponse.getEntity()).thenReturn(new StringEntity("{'var' : 'val'}")); JSONObjectWrapper jsonObjectWrapper = secureHttpHelper.executeHttpGet(HOST, PATH, getQueryParams(), null, AbstractBaseServiceHelper.JSON_PARSER); assertNotNull(jsonObjectWrapper); assertEquals("val", jsonObjectWrapper.getString("var")); verifyExecute(HttpGet.class); } @Test public void executeHttpGetThrowsServerException() throws ClientProtocolException, IOException { expectedException.expect(ServerException.class); expectedException.expect(new ServerExceptionMatcher(new ServerException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Server Error", "{'error' : 'server'}"))); when(httpClient.execute(httpGet)).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(getStatusLine(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Server Error")); when(httpResponse.getEntity()).thenReturn(new StringEntity("{'error' : 'server'}")); secureHttpHelper.executeHttpGet(HOST, PATH, getQueryParams(), null, AbstractBaseServiceHelper.JSON_PARSER); } @Test public void executeHttpGetThrowsClientException() throws ClientProtocolException, IOException { expectedException.expect(ClientException.class); expectedException.expect(new ClientExceptionMatcher(new ClientException(HttpStatus.SC_BAD_REQUEST, "Bad Request", "{'error' : 'client'}"))); when(httpClient.execute(httpGet)).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(getStatusLine(HttpStatus.SC_BAD_REQUEST, "Bad Request")); when(httpResponse.getEntity()).thenReturn(new StringEntity("{'error' : 'client'}")); secureHttpHelper.executeHttpGet(HOST, PATH, getQueryParams(), null, AbstractBaseServiceHelper.JSON_PARSER); } @Test public void executeHttpPost() throws ClientProtocolException, IOException { when(httpClient.execute(httpPost)).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(getStatusLine(HttpStatus.SC_OK, "OK")); when(httpResponse.getEntity()).thenReturn(new StringEntity("{'var' : 'val'}")); Map<String, String> requestHeaders = getRequestHeaders(); JSONObjectWrapper jsonObjectWrapper = secureHttpHelper.executeHttpPost(HOST, PATH, requestHeaders, getQueryParams(), null, null, AbstractBaseServiceHelper.JSON_PARSER); assertNotNull(jsonObjectWrapper); assertEquals("val", jsonObjectWrapper.getString("var")); for (String key : requestHeaders.keySet()) verify(httpPost, times(1)).setHeader(key, requestHeaders.get(key)); verifyExecute(HttpPost.class); } @Test public void getImage() throws ClientProtocolException, IOException { final String URI = "http://www.example.com/image.png"; when(httpClient.execute(httpGet)).thenReturn(httpResponse); when(httpResponse.getEntity()).thenReturn(httpEntity); when(httpEntity.getContent()).thenReturn(new InputStream() { @Override public int read() throws IOException { return -1; } }); secureHttpHelper.getImage(URI); ArgumentCaptor<HttpGet> httpGetArgCaptor = ArgumentCaptor.forClass(HttpGet.class); verify(httpClient, times(1)).execute(httpGetArgCaptor.capture()); HttpGet value = httpGetArgCaptor.getValue(); assertNotNull(value); assertEquals(URI, value.getURI().toASCIIString()); } @Test public void getImageThrowsIOException() throws ClientProtocolException, IOException { expectedException.expect(ClientException.class); final String URI = "http://www.example.com/image.png"; when(httpClient.execute(httpGet)).thenThrow(new IOException("Connection closed")); assertNull(secureHttpHelper.getImage(URI)); ArgumentCaptor<HttpGet> httpGetArgCaptor = ArgumentCaptor.forClass(HttpGet.class); verify(httpClient, times(1)).execute(httpGetArgCaptor.capture()); HttpGet value = httpGetArgCaptor.getValue(); assertNotNull(value); assertEquals(URI, value.getURI().toASCIIString()); } @Test public void getImageWithNullUrl() throws ClientProtocolException, IOException { assertNull(secureHttpHelper.getImage(null)); } }