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
49 final AtomicInteger authenticatorCounter = new AtomicInteger(0);
50
51
52 HttpClientRequest request = new HttpClientRequest(mockHttpClient, MethodType.GET, "http://url",
53 mock(CertificateFactory.class), mock(UserManager.class));
54
55
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
67 request.addAuthentication(authenticator);
68 request.addAuthentication(authenticator);
69
70
71 request.execute(EasyMock.createMock(ResponseHandler.class));
72
73
74 assertEquals("Two authenticator should be called.", 2, authenticatorCounter.intValue());
75 }
76
77 public void testConnectTimeout() throws IOException, ResponseException
78 {
79
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
96 assertEquals(ConnectTimeoutException.class, e.getCause().getClass());
97 assertEquals("errordescription", e.getMessage());
98 }
99 }
100
101 public void testReadTimeout() throws IOException, ResponseException
102 {
103
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
120 assertEquals(NoHttpResponseException.class, e.getCause().getClass());
121 assertEquals("errordescription", e.getMessage());
122 }
123 }
124
125 public void testHttpException() throws IOException, ResponseException
126 {
127
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
144 assertEquals(HttpException.class, e.getCause().getClass());
145 assertEquals("errordescription", e.getMessage());
146 }
147 }
148
149 public void testSocketException() throws IOException, ResponseException
150 {
151
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
168 assertEquals(SocketException.class, e.getCause().getClass());
169 assertEquals("errordescription", e.getMessage());
170 }
171 }
172
173 public void testStatusException() throws IOException, ResponseException
174 {
175
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
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
200 assertNotNull(e.getResponse());
201 assertEquals(400, e.getResponse().getStatusCode());
202 }
203 }
204
205 public void testMaxNumberOfRedirectionReached() throws IOException, ResponseException
206 {
207
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
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
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
234 }
235
236
237 mockControl.verify();
238 }
239
240 public void testNoFollowRedirect() throws IOException
241 {
242
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
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
260 try
261 {
262 request.execute(EasyMock.createMock(ResponseHandler.class));
263
264 }
265 catch (ResponseException e)
266 {
267 fail(e.getMessage());
268 }
269
270
271 mockControl.verify();
272 }
273
274 public void testFollowRedirectForPostMethodsNotPossible() throws Exception
275 {
276
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
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
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
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
349 }
350
351
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
361 }
362
363
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
373 }
374 }
375
376 public void testAddRequestParameters() throws IOException, ResponseException
377 {
378
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
395 HttpClientRequest request = createMockRequest(mockHttpClient, mockPostMethod, MethodType.POST, "http://url");
396
397
398 request.addRequestParameters("a", "b", "a", "b", "a", "c", "x", "y");
399 request.execute(EasyMock.createMock(ResponseHandler.class));
400
401
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 }