/* * Copyright (C) 2012 The Android Open Source Project * * 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 com.android.volley.toolbox; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.android.volley.Header; import com.android.volley.Request; import com.android.volley.Request.Method; import com.android.volley.mock.TestRequest; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FilterInputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class HurlStackTest { @Mock private HttpURLConnection mMockConnection; private HurlStack mHurlStack; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mMockConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); mHurlStack = new HurlStack() { @Override protected HttpURLConnection createConnection(URL url) { return mMockConnection; } @Override protected InputStream createInputStream( Request request, HttpURLConnection connection) { return new MonitoringInputStream( super.createInputStream(request, connection)); } @Override protected OutputStream createOutputStream( Request request, HttpURLConnection connection, int length) throws IOException { if (request instanceof MonitoredRequest) { return new MonitoringOutputStream( super.createOutputStream(request, connection, length), (MonitoredRequest) request, length); } return super.createOutputStream(request, connection, length); } }; } @Test public void connectionForDeprecatedGetRequest() throws Exception { TestRequest.DeprecatedGet request = new TestRequest.DeprecatedGet(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection, never()).setRequestMethod(anyString()); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForDeprecatedPostRequest() throws Exception { TestRequest.DeprecatedPost request = new TestRequest.DeprecatedPost(); assertEquals(request.getMethod(), Method.DEPRECATED_GET_OR_POST); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("POST"); verify(mMockConnection).setDoOutput(true); } @Test public void connectionForGetRequest() throws Exception { TestRequest.Get request = new TestRequest.Get(); assertEquals(request.getMethod(), Method.GET); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("GET"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForPostRequest() throws Exception { TestRequest.Post request = new TestRequest.Post(); assertEquals(request.getMethod(), Method.POST); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("POST"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForPostWithBodyRequest() throws Exception { TestRequest.PostWithBody request = new TestRequest.PostWithBody(); assertEquals(request.getMethod(), Method.POST); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("POST"); verify(mMockConnection).setDoOutput(true); } @Test public void connectionForPutRequest() throws Exception { TestRequest.Put request = new TestRequest.Put(); assertEquals(request.getMethod(), Method.PUT); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("PUT"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForPutWithBodyRequest() throws Exception { TestRequest.PutWithBody request = new TestRequest.PutWithBody(); assertEquals(request.getMethod(), Method.PUT); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("PUT"); verify(mMockConnection).setDoOutput(true); } @Test public void connectionForDeleteRequest() throws Exception { TestRequest.Delete request = new TestRequest.Delete(); assertEquals(request.getMethod(), Method.DELETE); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("DELETE"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForHeadRequest() throws Exception { TestRequest.Head request = new TestRequest.Head(); assertEquals(request.getMethod(), Method.HEAD); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("HEAD"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForOptionsRequest() throws Exception { TestRequest.Options request = new TestRequest.Options(); assertEquals(request.getMethod(), Method.OPTIONS); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("OPTIONS"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForTraceRequest() throws Exception { TestRequest.Trace request = new TestRequest.Trace(); assertEquals(request.getMethod(), Method.TRACE); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("TRACE"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForPatchRequest() throws Exception { TestRequest.Patch request = new TestRequest.Patch(); assertEquals(request.getMethod(), Method.PATCH); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("PATCH"); verify(mMockConnection, never()).setDoOutput(true); } @Test public void connectionForPatchWithBodyRequest() throws Exception { TestRequest.PatchWithBody request = new TestRequest.PatchWithBody(); assertEquals(request.getMethod(), Method.PATCH); mHurlStack.setConnectionParametersForRequest(mMockConnection, request); verify(mMockConnection).setRequestMethod("PATCH"); verify(mMockConnection).setDoOutput(true); } @Test public void executeRequestClosesConnection_connectionError() throws Exception { when(mMockConnection.getResponseCode()).thenThrow(new SocketTimeoutException()); try { mHurlStack.executeRequest( new TestRequest.Get(), Collections.emptyMap()); fail("Should have thrown exception"); } catch (IOException e) { verify(mMockConnection).disconnect(); } } @Test public void executeRequestClosesConnection_invalidResponseCode() throws Exception { when(mMockConnection.getResponseCode()).thenReturn(-1); try { mHurlStack.executeRequest( new TestRequest.Get(), Collections.emptyMap()); fail("Should have thrown exception"); } catch (IOException e) { verify(mMockConnection).disconnect(); } } @Test public void executeRequestClosesConnection_noResponseBody() throws Exception { when(mMockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_NO_CONTENT); mHurlStack.executeRequest(new TestRequest.Get(), Collections.emptyMap()); verify(mMockConnection).disconnect(); } @Test public void executeRequestClosesConnection_hasResponseBody() throws Exception { when(mMockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); when(mMockConnection.getInputStream()) .thenReturn(new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8))); HttpResponse response = mHurlStack.executeRequest( new TestRequest.Get(), Collections.emptyMap()); // Shouldn't be disconnected until the stream is consumed. verify(mMockConnection, never()).disconnect(); response.getContent().close(); verify(mMockConnection).disconnect(); } @Test public void convertHeaders() { Map> headers = new HashMap<>(); headers.put(null, Collections.singletonList("Ignored")); headers.put("HeaderA", Collections.singletonList("ValueA")); List values = new ArrayList<>(); values.add("ValueB_1"); values.add("ValueB_2"); headers.put("HeaderB", values); List
result = HurlStack.convertHeaders(headers); List
expected = new ArrayList<>(); expected.add(new Header("HeaderA", "ValueA")); expected.add(new Header("HeaderB", "ValueB_1")); expected.add(new Header("HeaderB", "ValueB_2")); assertEquals(expected, result); } @Test public void interceptResponseStream() throws Exception { when(mMockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); when(mMockConnection.getInputStream()) .thenReturn(new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8))); HttpResponse response = mHurlStack.executeRequest( new TestRequest.Get(), Collections.emptyMap()); assertTrue(response.getContent() instanceof MonitoringInputStream); } @Test public void interceptRequestStream() throws Exception { MonitoredRequest request = new MonitoredRequest(); mHurlStack.executeRequest(request, Collections.emptyMap()); assertTrue(request.totalRequestBytes > 0); assertEquals(request.totalRequestBytes, request.requestBytesRead); } private static class MonitoringInputStream extends FilterInputStream { private MonitoringInputStream(InputStream in) { super(in); } } private static class MonitoringOutputStream extends FilterOutputStream { private MonitoredRequest request; private MonitoringOutputStream(OutputStream out, MonitoredRequest request, int length) { super(out); this.request = request; this.request.totalRequestBytes = length; } @Override public void write(int b) throws IOException { this.request.requestBytesRead++; out.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { this.request.requestBytesRead += len; out.write(b, off, len); } } private static class MonitoredRequest extends TestRequest.PostWithBody { int requestBytesRead = 0; int totalRequestBytes = 0; } }