View Javadoc

1   package com.atlassian.sal.core.rest;
2   
3   import com.atlassian.sal.api.net.Request.MethodType;
4   import com.atlassian.sal.api.net.ResponseConnectTimeoutException;
5   import com.atlassian.sal.api.net.ResponseException;
6   import com.atlassian.sal.api.net.ResponseHandler;
7   import com.atlassian.sal.api.net.ResponseProtocolException;
8   import com.atlassian.sal.api.net.ResponseReadTimeoutException;
9   import com.atlassian.sal.api.net.ResponseStatusException;
10  import com.atlassian.sal.api.net.ResponseTransportException;
11  import com.atlassian.sal.api.user.UserManager;
12  import com.atlassian.sal.core.net.HttpClientRequest;
13  import com.atlassian.sal.core.net.HttpClientResponse;
14  import com.atlassian.sal.core.net.auth.HttpClientAuthenticator;
15  import com.atlassian.sal.core.trusted.CertificateFactory;
16  import junit.framework.TestCase;
17  
18  import org.apache.commons.httpclient.ConnectTimeoutException;
19  import org.apache.commons.httpclient.Header;
20  import org.apache.commons.httpclient.HttpClient;
21  import org.apache.commons.httpclient.HttpException;
22  import org.apache.commons.httpclient.HttpMethod;
23  import org.apache.commons.httpclient.NoHttpResponseException;
24  import org.apache.commons.httpclient.methods.GetMethod;
25  import org.apache.commons.httpclient.methods.PostMethod;
26  import org.apache.commons.httpclient.methods.PutMethod;
27  import org.easymock.classextension.EasyMock;
28  import org.easymock.classextension.IMocksControl;
29  import org.mockito.Mockito;
30  
31  import java.io.IOException;
32  import java.net.SocketException;
33  import java.util.concurrent.atomic.AtomicInteger;
34  
35  import static org.easymock.EasyMock.isA;
36  import static org.mockito.Mockito.mock;
37  
38  public class TestHttpClientRequest extends TestCase
39  {
40  
41      public void testAuthentication() throws IOException, ResponseException
42      {
43          final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
44          final HttpClient mockHttpClient = httpClientMockControl.createMock(HttpClient.class);
45          httpClientMockControl.replay();
46  
47  
48          // counter how many time was authentication called
49          final AtomicInteger authenticatorCounter = new AtomicInteger(0);
50  
51          // lets create new GET request to http://url
52          HttpClientRequest request = new HttpClientRequest(mockHttpClient, MethodType.GET, "http://url",
53                  mock(CertificateFactory.class), mock(UserManager.class));
54  
55          // this is our authenticator
56          final HttpClientAuthenticator authenticator = new HttpClientAuthenticator()
57          {
58              public void process(HttpClient httpClient, HttpMethod method)
59              {
60                  assertEquals("It should use mockClient", httpClient, mockHttpClient);
61                  assertTrue("We asked it for GetMethod", method instanceof GetMethod);
62                  authenticatorCounter.addAndGet(1);
63              }
64          };
65  
66          // lets add 2 authenticator to the request
67          request.addAuthentication(authenticator);
68          request.addAuthentication(authenticator);
69  
70          // and we are ready to execute the request
71          request.execute(EasyMock.createMock(ResponseHandler.class));
72  
73          // and assert that authenticators were used
74          assertEquals("Two authenticator should be called.", 2, authenticatorCounter.intValue());
75      }
76  
77      public void testConnectTimeout() throws IOException, ResponseException
78      {
79          // create HttpClient that will throw a ConnectTimeoutException
80          final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
81          final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
82          httpClientMock.executeMethod(isA(GetMethod.class));
83          httpClientMockControl.andThrow(new ConnectTimeoutException("errordescription"));
84          httpClientMockControl.replay();
85  
86          HttpClientRequest request = createMockRequest(httpClientMock, MethodType.GET, "http://url");
87  
88          try
89          {
90              request.execute(EasyMock.createMock(ResponseHandler.class));
91              fail("Should throw ResponseConnectTimeoutException");
92          }
93          catch (ResponseConnectTimeoutException e)
94          {
95              // expect Exception
96              assertEquals(ConnectTimeoutException.class, e.getCause().getClass());
97              assertEquals("errordescription", e.getMessage());
98          }
99      }
100 
101     public void testReadTimeout() throws IOException, ResponseException
102     {
103         // create HttpClient that will throw a NoHttpResponseException
104         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
105         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
106         httpClientMock.executeMethod(isA(GetMethod.class));
107         httpClientMockControl.andThrow(new NoHttpResponseException("errordescription"));
108         httpClientMockControl.replay();
109 
110         HttpClientRequest request = createMockRequest(httpClientMock, MethodType.GET, "http://url");
111 
112         try
113         {
114             request.execute(EasyMock.createMock(ResponseHandler.class));
115             fail("Should throw ResponseConnectTimeoutException");
116         }
117         catch (ResponseReadTimeoutException e)
118         {
119             // expect Exception
120             assertEquals(NoHttpResponseException.class, e.getCause().getClass());
121             assertEquals("errordescription", e.getMessage());
122         }
123     }
124 
125     public void testHttpException() throws IOException, ResponseException
126     {
127         // create HttpClient that will throw an HttpException
128         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
129         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
130         httpClientMock.executeMethod(isA(GetMethod.class));
131         httpClientMockControl.andThrow(new HttpException("errordescription"));
132         httpClientMockControl.replay();
133 
134         HttpClientRequest request = createMockRequest(httpClientMock, MethodType.GET, "http://url");
135 
136         try
137         {
138             request.execute(EasyMock.createMock(ResponseHandler.class));
139             fail("Should throw ResponseProtocolException");
140         }
141         catch (ResponseProtocolException e)
142         {
143             // expect Exception
144             assertEquals(HttpException.class, e.getCause().getClass());
145             assertEquals("errordescription", e.getMessage());
146         }
147     }
148 
149     public void testSocketException() throws IOException, ResponseException
150     {
151         // create HttpClient that will throw a SocketException
152         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
153         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
154         httpClientMock.executeMethod(isA(GetMethod.class));
155         httpClientMockControl.andThrow(new SocketException("errordescription"));
156         httpClientMockControl.replay();
157 
158         HttpClientRequest request = createMockRequest(httpClientMock, MethodType.GET, "http://url");
159 
160         try
161         {
162             request.execute(EasyMock.createMock(ResponseHandler.class));
163             fail("Should throw ResponseTransportException");
164         }
165         catch (ResponseTransportException e)
166         {
167             // expect Exception
168             assertEquals(SocketException.class, e.getCause().getClass());
169             assertEquals("errordescription", e.getMessage());
170         }
171     }
172 
173     public void testStatusException() throws IOException, ResponseException
174     {
175         // create mock GetMethod that returns a 400 error
176         final IMocksControl mockControl = EasyMock.createNiceControl();
177         final GetMethod mockGetMethod = mockControl.createMock(GetMethod.class);
178         mockGetMethod.getStatusCode();
179         mockControl.andReturn(400);
180         mockControl.anyTimes();
181         mockControl.replay();
182 
183         // create HttpClient that will return this response
184         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
185         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
186         httpClientMock.executeMethod(mockGetMethod);
187         httpClientMockControl.andReturn(400);
188         httpClientMockControl.replay();
189 
190         HttpClientRequest request = createMockRequest(httpClientMock, mockGetMethod, MethodType.GET, "http://url");
191 
192         try
193         {
194             request.execute();
195             fail("Should throw ResponseStatusException");
196         }
197         catch (ResponseStatusException e)
198         {
199             // expect Exception
200             assertNotNull(e.getResponse());
201             assertEquals(400, e.getResponse().getStatusCode());
202         }
203     }
204     
205     public void testMaxNumberOfRedirectionReached() throws IOException, ResponseException
206     {
207         // create mock GetMethod - it should redirect few times
208         final IMocksControl mockControl = EasyMock.createNiceControl();
209         final GetMethod mockGetMethod = mockControl.createMock(GetMethod.class);
210         mockGetMethod.getResponseHeader("location");
211         mockControl.andReturn(new Header("location", "http://someRedirectionUrl"));
212         mockControl.times(HttpClientRequest.MAX_REDIRECTS);
213         mockControl.replay();
214 
215         // create HttpClient that will return 301 Moved Permanently
216         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
217         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
218         httpClientMock.executeMethod(mockGetMethod);
219         httpClientMockControl.andReturn(302);
220         httpClientMockControl.times(HttpClientRequest.MAX_REDIRECTS);
221         httpClientMockControl.replay();
222 
223         HttpClientRequest request = createMockRequest(httpClientMock, mockGetMethod, MethodType.GET, "http://url");
224 
225         // now use it
226         try
227         {
228             request.execute(EasyMock.createMock(ResponseHandler.class));
229             fail("Should throw ResponseProtocolException - maximum retries reached.");
230         }
231         catch (ResponseProtocolException e)
232         {
233             // expect Exception
234         }
235 
236         // and assert results
237         mockControl.verify();
238     }
239     
240     public void testNoFollowRedirect() throws IOException
241     {
242         // create mock GetMethod - it should not redirect automatically
243         final IMocksControl mockControl = EasyMock.createNiceControl();
244         final GetMethod mockGetMethod = mockControl.createMock(GetMethod.class);
245         mockGetMethod.getResponseHeader("location");
246         mockControl.andReturn(new Header("location", "http://someRedirectionUrl")).anyTimes();
247         mockControl.replay();
248 
249         // create HttpClient that will return 301 Moved Permanently
250         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
251         final HttpClient httpClientMock = httpClientMockControl.createMock(HttpClient.class);
252         httpClientMock.executeMethod(mockGetMethod);
253         httpClientMockControl.andReturn(302).anyTimes();
254         httpClientMockControl.replay();
255 
256         HttpClientRequest request = createMockRequest(httpClientMock, mockGetMethod, MethodType.GET, "http://url");
257         request.setFollowRedirects(false);
258                
259         // now use it
260         try
261         {
262             request.execute(EasyMock.createMock(ResponseHandler.class));
263             
264         }
265         catch (ResponseException e)
266         {
267             fail(e.getMessage());
268         }
269 
270         // and assert results
271         mockControl.verify();
272     }
273 
274     public void testFollowRedirectForPostMethodsNotPossible() throws Exception
275     {
276         // create a request that will return mockGetMethod
277         HttpClientRequest request = createMockRequest(MethodType.POST, "http://url");
278         try
279         {
280             request.setFollowRedirects(true);
281             fail("Should have thrown an exception because we can't follow redirects for Post methods");
282         } catch (IllegalStateException ex)
283         {
284             //Expected
285             assertEquals("Entity enclosing requests cannot be redirected without user intervention!", ex.getMessage());
286         }
287     }
288 
289 
290     public void testFollowRedirectForPutMethodsNotPossible() throws Exception
291     {
292         HttpClientRequest request = createMockRequest(MethodType.PUT, "http://url");
293 
294         try
295         {
296             request.setFollowRedirects(true);
297             fail("Should have thrown an exception because we can't follow redirects for Post methods");
298         } catch (IllegalStateException ex)
299         {
300             //Expected
301             assertEquals("Entity enclosing requests cannot be redirected without user intervention!", ex.getMessage());
302         }
303     }
304 
305     public void testExecutePostMethodNoFollowRedirects() throws Exception
306     {
307         final HttpClient httpClientMock = mock(HttpClient.class);
308         final PostMethod postMethod = mock(PostMethod.class);
309 
310         HttpClientRequest request = createMockRequest(httpClientMock, postMethod, MethodType.POST, "http://url");
311 
312         request.execute(new ResponseHandler<HttpClientResponse>(){
313             public void handle(final HttpClientResponse response) throws ResponseException
314             {
315 
316             }
317         });
318         Mockito.verify(postMethod).setFollowRedirects(false);
319     }
320 
321     public void testExecutePutMethodNoFollowRedirects() throws Exception
322     {
323         final HttpClient httpClientMock = mock(HttpClient.class);
324         final PutMethod putMethod = mock(PutMethod.class);
325 
326         HttpClientRequest request = createMockRequest(httpClientMock, putMethod, MethodType.PUT, "http://url");
327 
328         request.execute(new ResponseHandler<HttpClientResponse>(){
329             public void handle(final HttpClientResponse response) throws ResponseException
330             {
331 
332             }
333         });
334         Mockito.verify(putMethod).setFollowRedirects(false);
335     }
336 
337     public void testAddRequestParametersFails()
338     {
339         // Lets try to add parameters to GET method
340         try
341         {
342             HttpClientRequest request = createMockRequest(MethodType.GET, "http://url");
343             request.addRequestParameters("doIt", "quickly!");
344             fail("Should throw exception that only the POST method can have parameters.");
345         }
346         catch (UnsupportedOperationException e)
347         {
348             // expected
349         }
350 
351         // Lets try to add parameters to PUT method
352         try
353         {
354             HttpClientRequest request = createMockRequest(MethodType.PUT, "http://url");
355             request.addRequestParameters("Isaid", "doIt", "now");
356             fail("Should throw exception that only the POST method can have parameters.");
357         }
358         catch (UnsupportedOperationException e)
359         {
360             // expected
361         }
362 
363         // Lets try to add uneven amount of parameters to POST method
364         try
365         {
366             HttpClientRequest request = createMockRequest(MethodType.POST, "http://url");
367             request.addRequestParameters("doIt", "quickly!", "now");
368             fail("Should throw exception that You must enter an even number of arguments.");
369         }
370         catch (IllegalArgumentException e)
371         {
372             // expected
373         }
374     }
375 
376     public void testAddRequestParameters() throws IOException, ResponseException
377     {
378         // create mock PostMethod - someone should call addParamater() on it
379         final IMocksControl mockControl = EasyMock.createNiceControl();
380         final PostMethod mockPostMethod = mockControl.createMock(PostMethod.class);
381         mockPostMethod.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
382         mockPostMethod.addParameter("a", "b");
383         mockPostMethod.addParameter("a", "b");
384         mockPostMethod.addParameter("a", "c");
385         mockPostMethod.addParameter("x", "y");
386         mockControl.replay();
387 
388 
389         final IMocksControl httpClientMockControl = EasyMock.createNiceControl();
390         final HttpClient mockHttpClient = httpClientMockControl.createMock(HttpClient.class);
391         httpClientMockControl.replay();
392 
393 
394         // create a request that will return mockPostMethod
395         HttpClientRequest request = createMockRequest(mockHttpClient, mockPostMethod, MethodType.POST, "http://url");
396 
397         // now use it
398         request.addRequestParameters("a", "b", "a", "b", "a", "c", "x", "y");
399         request.execute(EasyMock.createMock(ResponseHandler.class));
400 
401         // and assert results
402         mockControl.verify();
403     }
404 
405     private HttpClientRequest createMockRequest(MethodType methodType, String url)
406     {
407         return createMockRequest(EasyMock.createMock(HttpClient.class), methodType, url);
408     }
409 
410     private HttpClientRequest createMockRequest(HttpClient client, MethodType methodType, String url)
411     {
412         return new HttpClientRequest(client, methodType, url,
413                                      mock(CertificateFactory.class), mock(UserManager.class));
414     }
415 
416     private HttpClientRequest createMockRequest(HttpClient client, final HttpMethod method, MethodType methodType,
417                                                 String url)
418     {
419         return new HttpClientRequest(client, methodType, url, mock(CertificateFactory.class), mock(UserManager.class))
420             {
421                 @Override
422                 protected HttpMethod makeMethod()
423                 {
424                     return method;
425                 }
426             };
427     }
428 }