Home | History | Annotate | Download | only in toolbox
      1 package com.android.volley.toolbox;
      2 
      3 import static org.junit.Assert.assertEquals;
      4 import static org.junit.Assert.fail;
      5 import static org.mockito.ArgumentMatchers.any;
      6 import static org.mockito.ArgumentMatchers.anyString;
      7 import static org.mockito.Mockito.doAnswer;
      8 import static org.mockito.Mockito.doReturn;
      9 import static org.mockito.Mockito.spy;
     10 import static org.mockito.Mockito.when;
     11 
     12 import com.android.volley.Request;
     13 import com.android.volley.RetryPolicy;
     14 import java.io.IOException;
     15 import java.io.OutputStream;
     16 import java.net.HttpURLConnection;
     17 import java.net.URL;
     18 import java.util.Collections;
     19 import java.util.HashMap;
     20 import java.util.List;
     21 import java.util.Map;
     22 import org.apache.http.Header;
     23 import org.apache.http.HttpRequest;
     24 import org.apache.http.client.HttpClient;
     25 import org.apache.http.client.methods.HttpUriRequest;
     26 import org.junit.Before;
     27 import org.junit.Test;
     28 import org.junit.runner.RunWith;
     29 import org.mockito.Mock;
     30 import org.mockito.MockitoAnnotations;
     31 import org.mockito.Spy;
     32 import org.mockito.invocation.InvocationOnMock;
     33 import org.mockito.stubbing.Answer;
     34 import org.robolectric.RobolectricTestRunner;
     35 
     36 /** Tests to validate that HttpStack implementations conform with expected behavior. */
     37 @RunWith(RobolectricTestRunner.class)
     38 public class HttpStackConformanceTest {
     39     @Mock private RetryPolicy mMockRetryPolicy;
     40     @Mock private Request mMockRequest;
     41 
     42     @Mock private HttpURLConnection mMockConnection;
     43     @Mock private OutputStream mMockOutputStream;
     44     @Spy private HurlStack mHurlStack = new HurlStack();
     45 
     46     @Mock private HttpClient mMockHttpClient;
     47     private HttpClientStack mHttpClientStack;
     48 
     49     private final TestCase[] mTestCases =
     50             new TestCase[] {
     51                 // TestCase for HurlStack.
     52                 new TestCase() {
     53                     @Override
     54                     public HttpStack getStack() {
     55                         return mHurlStack;
     56                     }
     57 
     58                     @Override
     59                     public void setOutputHeaderMap(final Map<String, String> outputHeaderMap) {
     60                         doAnswer(
     61                                         new Answer<Void>() {
     62                                             @Override
     63                                             public Void answer(InvocationOnMock invocation) {
     64                                                 outputHeaderMap.put(
     65                                                         invocation.<String>getArgument(0),
     66                                                         invocation.<String>getArgument(1));
     67                                                 return null;
     68                                             }
     69                                         })
     70                                 .when(mMockConnection)
     71                                 .setRequestProperty(anyString(), anyString());
     72                         doAnswer(
     73                                         new Answer<Map<String, List<String>>>() {
     74                                             @Override
     75                                             public Map<String, List<String>> answer(
     76                                                     InvocationOnMock invocation) {
     77                                                 Map<String, List<String>> result = new HashMap<>();
     78                                                 for (Map.Entry<String, String> entry :
     79                                                         outputHeaderMap.entrySet()) {
     80                                                     result.put(
     81                                                             entry.getKey(),
     82                                                             Collections.singletonList(
     83                                                                     entry.getValue()));
     84                                                 }
     85                                                 return result;
     86                                             }
     87                                         })
     88                                 .when(mMockConnection)
     89                                 .getRequestProperties();
     90                     }
     91                 },
     92 
     93                 // TestCase for HttpClientStack.
     94                 new TestCase() {
     95                     @Override
     96                     public HttpStack getStack() {
     97                         return mHttpClientStack;
     98                     }
     99 
    100                     @Override
    101                     public void setOutputHeaderMap(final Map<String, String> outputHeaderMap) {
    102                         try {
    103                             doAnswer(
    104                                             new Answer<Void>() {
    105                                                 @Override
    106                                                 public Void answer(InvocationOnMock invocation)
    107                                                         throws Throwable {
    108                                                     HttpRequest request = invocation.getArgument(0);
    109                                                     for (Header header : request.getAllHeaders()) {
    110                                                         if (outputHeaderMap.containsKey(
    111                                                                 header.getName())) {
    112                                                             fail(
    113                                                                     "Multiple values for header "
    114                                                                             + header.getName());
    115                                                         }
    116                                                         outputHeaderMap.put(
    117                                                                 header.getName(),
    118                                                                 header.getValue());
    119                                                     }
    120                                                     return null;
    121                                                 }
    122                                             })
    123                                     .when(mMockHttpClient)
    124                                     .execute(any(HttpUriRequest.class));
    125                         } catch (IOException e) {
    126                             throw new RuntimeException(e);
    127                         }
    128                     }
    129                 }
    130             };
    131 
    132     @Before
    133     public void setUp() throws Exception {
    134         MockitoAnnotations.initMocks(this);
    135         mHttpClientStack = spy(new HttpClientStack(mMockHttpClient));
    136 
    137         doReturn(mMockConnection).when(mHurlStack).createConnection(any(URL.class));
    138         doReturn(mMockOutputStream).when(mMockConnection).getOutputStream();
    139         when(mMockRequest.getUrl()).thenReturn("http://127.0.0.1");
    140         when(mMockRequest.getRetryPolicy()).thenReturn(mMockRetryPolicy);
    141     }
    142 
    143     @Test
    144     public void headerPrecedence() throws Exception {
    145         Map<String, String> additionalHeaders = new HashMap<>();
    146         additionalHeaders.put("A", "AddlA");
    147         additionalHeaders.put("B", "AddlB");
    148 
    149         Map<String, String> requestHeaders = new HashMap<>();
    150         requestHeaders.put("A", "RequestA");
    151         requestHeaders.put("C", "RequestC");
    152         when(mMockRequest.getHeaders()).thenReturn(requestHeaders);
    153 
    154         when(mMockRequest.getMethod()).thenReturn(Request.Method.POST);
    155         when(mMockRequest.getBody()).thenReturn(new byte[0]);
    156         when(mMockRequest.getBodyContentType()).thenReturn("BodyContentType");
    157 
    158         for (TestCase testCase : mTestCases) {
    159             // Test once without a Content-Type header in getHeaders().
    160             Map<String, String> combinedHeaders = new HashMap<>();
    161             testCase.setOutputHeaderMap(combinedHeaders);
    162 
    163             testCase.getStack().performRequest(mMockRequest, additionalHeaders);
    164 
    165             Map<String, String> expectedHeaders = new HashMap<>();
    166             expectedHeaders.put("A", "RequestA");
    167             expectedHeaders.put("B", "AddlB");
    168             expectedHeaders.put("C", "RequestC");
    169             expectedHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "BodyContentType");
    170 
    171             assertEquals(expectedHeaders, combinedHeaders);
    172 
    173             // Reset and test again with a Content-Type header in getHeaders().
    174             combinedHeaders.clear();
    175 
    176             requestHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "RequestContentType");
    177             expectedHeaders.put(HttpHeaderParser.HEADER_CONTENT_TYPE, "RequestContentType");
    178 
    179             testCase.getStack().performRequest(mMockRequest, additionalHeaders);
    180             assertEquals(expectedHeaders, combinedHeaders);
    181 
    182             // Clear the Content-Type header for the next TestCase.
    183             requestHeaders.remove(HttpHeaderParser.HEADER_CONTENT_TYPE);
    184         }
    185     }
    186 
    187     private interface TestCase {
    188         HttpStack getStack();
    189 
    190         void setOutputHeaderMap(Map<String, String> outputHeaderMap);
    191     }
    192 }
    193