From 65d9fb8addc5e338cf485811379484b8fd5e3ccc Mon Sep 17 00:00:00 2001 From: Anonymous Date: Mon, 18 Jun 2018 16:19:27 -0700 Subject: Import of Volley from GitHub to AOSP. - b080a3488b0f82e0ef70191e8848c631376e80e0 Improve error message for null keys/values in getParams(... by Jeff Davidson - 2695d3cee7965418c01294a3c8b1ac191216ec6a Fix crash when using HurlStack with POST requests. (#202) by Jeff Davidson - 0c32d6a8865ebe0daf320d2bd7e32368e0cc31ba Re-raise swallowed interrupts and log warnings for spurio... by Jeff Davidson - 608f9827eadc869b4876f666f4d1a8bfafbeab2b Flesh out RetryPolicy's Javadoc. (#194) by Jeff Davidson - 0819be69fb7919db46778e970c169b5c0c3b9f71 Prevent duplicated/conflicting HTTP headers for HurlStack... by Jeff Davidson - cb1df92f5f18fc125441950a2fd53f3daa73e809 Use different cache keys for different methods. (#191) by Jeff Davidson - a0f4d39af7fce1649c45fa4eeaffa4d173c05f95 Add @Nullable annotations where necessary. (#185) by hackbar <7153163+hackbar@users.noreply.github.com> GitOrigin-RevId: b080a3488b0f82e0ef70191e8848c631376e80e0 Change-Id: I0767443663d2118958f850dcf87b7ba89d9860b4 --- src/test/java/com/android/volley/RequestTest.java | 96 ++++++++++- .../volley/toolbox/HttpStackConformanceTest.java | 192 +++++++++++++++++++++ 2 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/android/volley/toolbox/HttpStackConformanceTest.java (limited to 'src/test/java/com') diff --git a/src/test/java/com/android/volley/RequestTest.java b/src/test/java/com/android/volley/RequestTest.java index e2dd655..382d9da 100644 --- a/src/test/java/com/android/volley/RequestTest.java +++ b/src/test/java/com/android/volley/RequestTest.java @@ -20,7 +20,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.android.volley.Request.Method; import com.android.volley.Request.Priority; +import java.util.Collections; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -84,9 +87,30 @@ public class RequestTest { assertFalse(0 == goodProtocol.getTrafficStatsTag()); } + @Test + public void getCacheKey() { + assertEquals( + "http://example.com", + new UrlParseRequest(Method.GET, "http://example.com").getCacheKey()); + assertEquals( + "http://example.com", + new UrlParseRequest(Method.DEPRECATED_GET_OR_POST, "http://example.com") + .getCacheKey()); + assertEquals( + "1-http://example.com", + new UrlParseRequest(Method.POST, "http://example.com").getCacheKey()); + assertEquals( + "2-http://example.com", + new UrlParseRequest(Method.PUT, "http://example.com").getCacheKey()); + } + private static class UrlParseRequest extends Request { - public UrlParseRequest(String url) { - super(Request.Method.GET, url, null); + UrlParseRequest(String url) { + this(Method.GET, url); + } + + UrlParseRequest(int method, String url) { + super(method, url, null); } @Override @@ -97,4 +121,72 @@ public class RequestTest { return null; } } + + @Test + public void nullKeyInPostParams() throws Exception { + Request request = + new Request(Method.POST, "url", null) { + @Override + protected void deliverResponse(Object response) {} + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + return null; + } + + @Override + protected Map getParams() { + return Collections.singletonMap(null, "value"); + } + + @Override + protected Map getPostParams() { + return Collections.singletonMap(null, "value"); + } + }; + try { + request.getBody(); + } catch (IllegalArgumentException e) { + // expected + } + try { + request.getPostBody(); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void nullValueInPostParams() throws Exception { + Request request = + new Request(Method.POST, "url", null) { + @Override + protected void deliverResponse(Object response) {} + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + return null; + } + + @Override + protected Map getParams() { + return Collections.singletonMap("key", null); + } + + @Override + protected Map getPostParams() { + return Collections.singletonMap("key", null); + } + }; + try { + request.getBody(); + } catch (IllegalArgumentException e) { + // expected + } + try { + request.getPostBody(); + } catch (IllegalArgumentException e) { + // expected + } + } } diff --git a/src/test/java/com/android/volley/toolbox/HttpStackConformanceTest.java b/src/test/java/com/android/volley/toolbox/HttpStackConformanceTest.java new file mode 100644 index 0000000..6794af8 --- /dev/null +++ b/src/test/java/com/android/volley/toolbox/HttpStackConformanceTest.java @@ -0,0 +1,192 @@ +package com.android.volley.toolbox; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.android.volley.Request; +import com.android.volley.RetryPolicy; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.http.Header; +import org.apache.http.HttpRequest; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +/** Tests to validate that HttpStack implementations conform with expected behavior. */ +@RunWith(RobolectricTestRunner.class) +public class HttpStackConformanceTest { + @Mock private RetryPolicy mMockRetryPolicy; + @Mock private Request mMockRequest; + + @Mock private HttpURLConnection mMockConnection; + @Mock private OutputStream mMockOutputStream; + @Spy private HurlStack mHurlStack = new HurlStack(); + + @Mock private HttpClient mMockHttpClient; + private HttpClientStack mHttpClientStack; + + private final TestCase[] mTestCases = + new TestCase[] { + // TestCase for HurlStack. + new TestCase() { + @Override + public HttpStack getStack() { + return mHurlStack; + } + + @Override + public void setOutputHeaderMap(final Map outputHeaderMap) { + doAnswer( + new Answer() { + @Override + public Void answer(InvocationOnMock invocation) { + outputHeaderMap.put( + invocation.getArgument(0), + invocation.getArgument(1)); + return null; + } + }) + .when(mMockConnection) + .setRequestProperty(anyString(), anyString()); + doAnswer( + new Answer>>() { + @Override + public Map> answer( + InvocationOnMock invocation) { + Map> result = new HashMap<>(); + for (Map.Entry entry : + outputHeaderMap.entrySet()) { + result.put( + entry.getKey(), + Collections.singletonList( + entry.getValue())); + } + return result; + } + }) + .when(mMockConnection) + .getRequestProperties(); + } + }, + + // TestCase for HttpClientStack. + new TestCase() { + @Override + public HttpStack getStack() { + return mHttpClientStack; + } + + @Override + public void setOutputHeaderMap(final Map outputHeaderMap) { + try { + doAnswer( + new Answer() { + @Override + public Void answer(InvocationOnMock invocation) + throws Throwable { + HttpRequest request = invocation.getArgument(0); + for (Header header : request.getAllHeaders()) { + if (outputHeaderMap.containsKey( + header.getName())) { + fail( + "Multiple values for header " + + header.getName()); + } + outputHeaderMap.put( + header.getName(), + header.getValue()); + } + return null; + } + }) + .when(mMockHttpClient) + .execute(any(HttpUriRequest.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + }; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mHttpClientStack = spy(new HttpClientStack(mMockHttpClient)); + + doReturn(mMockConnection).when(mHurlStack).createConnection(any(URL.class)); + doReturn(mMockOutputStream).when(mMockConnection).getOutputStream(); + when(mMockRequest.getUrl()).thenReturn("http://127.0.0.1"); + when(mMockRequest.getRetryPolicy()).thenReturn(mMockRetryPolicy); + } + + @Test + public void headerPrecedence() throws Exception { + Map additionalHeaders = new HashMap<>(); + additionalHeaders.put("A", "AddlA"); + additionalHeaders.put("B", "AddlB"); + + Map requestHeaders = new HashMap<>(); + requestHeaders.put("A", "RequestA"); + requestHeaders.put("C", "RequestC"); + when(mMockRequest.getHeaders()).thenReturn(requestHeaders); + + when(mMockRequest.getMethod()).thenReturn(Request.Method.POST); + when(mMockRequest.getBody()).thenReturn(new byte[0]); + when(mMockRequest.getBodyContentType()).thenReturn("BodyContentType"); + + for (TestCase testCase : mTestCases) { + // Test once without a Content-Type header in getHeaders(). + Map combinedHeaders = new HashMap<>(); + testCase.setOutputHeaderMap(combinedHeaders); + + testCase.getStack().performRequest(mMockRequest, additionalHeaders); + + Map expectedHeaders = new HashMap<>(); + expectedHeaders.put("A", "RequestA"); + expectedHeaders.put("B", "AddlB"); + expectedHeaders.put("C", "RequestC"); + expectedHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "BodyContentType"); + + assertEquals(expectedHeaders, combinedHeaders); + + // Reset and test again with a Content-Type header in getHeaders(). + combinedHeaders.clear(); + + requestHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "RequestContentType"); + expectedHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "RequestContentType"); + + testCase.getStack().performRequest(mMockRequest, additionalHeaders); + assertEquals(expectedHeaders, combinedHeaders); + + // Clear the Content-Type header for the next TestCase. + requestHeaders.remove(HttpHeaderParser.HEADER_CONTENT_TYPE); + } + } + + private interface TestCase { + HttpStack getStack(); + + void setOutputHeaderMap(Map outputHeaderMap); + } +} -- cgit v1.2.3