View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.nio.protocol;
29  
30  import java.io.IOException;
31  import java.net.SocketTimeoutException;
32  import java.util.Queue;
33  
34  import org.apache.http.ConnectionReuseStrategy;
35  import org.apache.http.HttpEntityEnclosingRequest;
36  import org.apache.http.HttpException;
37  import org.apache.http.HttpRequest;
38  import org.apache.http.HttpResponse;
39  import org.apache.http.HttpResponseFactory;
40  import org.apache.http.HttpStatus;
41  import org.apache.http.HttpVersion;
42  import org.apache.http.concurrent.Cancellable;
43  import org.apache.http.impl.DefaultHttpResponseFactory;
44  import org.apache.http.message.BasicHttpEntityEnclosingRequest;
45  import org.apache.http.message.BasicHttpRequest;
46  import org.apache.http.message.BasicHttpResponse;
47  import org.apache.http.nio.ContentDecoder;
48  import org.apache.http.nio.ContentEncoder;
49  import org.apache.http.nio.NHttpConnection;
50  import org.apache.http.nio.NHttpServerConnection;
51  import org.apache.http.nio.entity.NStringEntity;
52  import org.apache.http.nio.protocol.HttpAsyncService.Incoming;
53  import org.apache.http.nio.protocol.HttpAsyncService.Outgoing;
54  import org.apache.http.nio.protocol.HttpAsyncService.PipelineEntry;
55  import org.apache.http.nio.protocol.HttpAsyncService.State;
56  import org.apache.http.nio.reactor.SessionBufferStatus;
57  import org.apache.http.protocol.BasicHttpContext;
58  import org.apache.http.protocol.HTTP;
59  import org.apache.http.protocol.HttpContext;
60  import org.apache.http.protocol.HttpCoreContext;
61  import org.apache.http.protocol.HttpProcessor;
62  import org.junit.After;
63  import org.junit.Assert;
64  import org.junit.Before;
65  import org.junit.Test;
66  import org.mockito.ArgumentCaptor;
67  import org.mockito.ArgumentMatcher;
68  import org.mockito.Matchers;
69  import org.mockito.Mockito;
70  
71  public class TestHttpAsyncService {
72  
73      private UriHttpAsyncRequestHandlerMapper handlerResolver;
74      private HttpAsyncService protocolHandler;
75      private HttpProcessor httpProcessor;
76      private ConnectionReuseStrategy reuseStrategy;
77      private HttpResponseFactory responseFactory;
78      private HttpContext connContext;
79      private NHttpServerConnection conn;
80      private HttpAsyncRequestHandler<Object> requestHandler;
81      private HttpAsyncRequestConsumer<Object> requestConsumer;
82      private HttpAsyncResponseProducer responseProducer;
83      private ContentEncoder encoder;
84      private ContentDecoder decoder;
85      private Cancellable cancellable;
86  
87      @SuppressWarnings("unchecked")
88      @Before
89      public void setUp() throws Exception {
90          this.requestHandler = Mockito.mock(HttpAsyncRequestHandler.class);
91          this.requestConsumer = Mockito.mock(HttpAsyncRequestConsumer.class);
92          this.responseProducer = Mockito.mock(HttpAsyncResponseProducer.class);
93          this.handlerResolver = new UriHttpAsyncRequestHandlerMapper();
94          this.handlerResolver.register("/", this.requestHandler);
95          this.httpProcessor = Mockito.mock(HttpProcessor.class);
96          this.reuseStrategy = Mockito.mock(ConnectionReuseStrategy.class);
97          this.responseFactory = DefaultHttpResponseFactory.INSTANCE;
98          this.protocolHandler = new HttpAsyncService(
99                  this.httpProcessor, this.reuseStrategy, this.responseFactory, this.handlerResolver, null);
100         this.connContext = new BasicHttpContext();
101         this.conn = Mockito.mock(NHttpServerConnection.class);
102         this.encoder = Mockito.mock(ContentEncoder.class);
103         this.decoder = Mockito.mock(ContentDecoder.class);
104         this.cancellable = Mockito.mock(Cancellable.class);
105 
106         Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
107     }
108 
109     @After
110     public void tearDown() throws Exception {
111     }
112 
113     @Test(expected=IllegalArgumentException.class)
114     public void testInvalidConstruction() throws Exception {
115         new HttpAsyncService(null, this.reuseStrategy, this.responseFactory, this.handlerResolver, null);
116     }
117 
118     @Test
119     public void testConnected() throws Exception {
120         this.protocolHandler.connected(this.conn);
121 
122         final State state = (State) this.connContext.getAttribute(
123                 HttpAsyncService.HTTP_EXCHANGE_STATE);
124         Assert.assertNotNull(state);
125         Assert.assertEquals(MessageState.READY, state.getRequestState());
126         Assert.assertEquals(MessageState.READY, state.getResponseState());
127         Assert.assertEquals("[incoming READY; outgoing READY]", state.toString());
128     }
129 
130     @Test
131     public void testClosed() throws Exception {
132         final State state = new State();
133         state.setRequestState(MessageState.COMPLETED);
134         state.setResponseState(MessageState.COMPLETED);
135         final HttpContext exchangeContext = new BasicHttpContext();
136 
137         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
138         final Incoming incoming = new Incoming(
139                 request, this.requestHandler, this.requestConsumer, exchangeContext);
140         state.setIncoming(incoming);
141         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
142         final Outgoing outgoing = new Outgoing(
143                 request, response, this.responseProducer, exchangeContext);
144         state.setOutgoing(outgoing);
145         state.setCancellable(this.cancellable);
146         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
147 
148         this.protocolHandler.closed(this.conn);
149 
150         Mockito.verify(this.requestConsumer).close();
151         Mockito.verify(this.responseProducer).close();
152         Mockito.verify(this.cancellable).cancel();
153     }
154 
155     @Test
156     public void testHttpExceptionHandling() throws Exception {
157         final State state = new State();
158         state.setRequestState(MessageState.READY);
159         state.setResponseState(MessageState.READY);
160         final HttpContext exchangeContext = new BasicHttpContext();
161         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
162         final Incoming incoming = new Incoming(
163                 request, this.requestHandler, this.requestConsumer, exchangeContext);
164         state.setIncoming(incoming);
165         state.setCancellable(this.cancellable);
166         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
167 
168         final HttpException httpex = new HttpException();
169         this.protocolHandler.exception(this.conn, httpex);
170 
171         Assert.assertEquals(MessageState.READY, state.getRequestState());
172         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
173         final Outgoing outgoing = state.getOutgoing();
174         Assert.assertNotNull(outgoing);
175         Assert.assertNotNull(outgoing.getProducer());
176         Assert.assertNotNull(outgoing.getResponse());
177         Assert.assertEquals(500, outgoing.getResponse().getStatusLine().getStatusCode());
178 
179         Mockito.verify(this.requestConsumer).failed(httpex);
180         Mockito.verify(this.requestConsumer).close();
181         Mockito.verify(this.cancellable).cancel();
182         Mockito.verify(this.conn, Mockito.never()).shutdown();
183         Mockito.verify(this.conn, Mockito.never()).close();
184     }
185 
186     @Test
187     public void testExceptionHandlingNoState() throws Exception {
188         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, null);
189 
190         final Exception ex = new Exception("Oopsie");
191         this.protocolHandler.exception(conn, ex);
192 
193         Mockito.verify(conn).getContext();
194         Mockito.verify(conn).shutdown();
195         Mockito.verifyNoMoreInteractions(conn);
196     }
197 
198     @Test
199     public void testExceptionHandlingRuntimeException() throws Exception {
200         final State state = new State();
201         state.setRequestState(MessageState.READY);
202         state.setResponseState(MessageState.READY);
203         final HttpContext exchangeContext = new BasicHttpContext();
204         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
205         final Incoming incoming = new Incoming(
206                 request, this.requestHandler, this.requestConsumer, exchangeContext);
207         state.setIncoming(incoming);
208         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
209         final Outgoing outgoing = new Outgoing(
210                 request, response, this.responseProducer, exchangeContext);
211         state.setOutgoing(outgoing);
212         state.setCancellable(this.cancellable);
213         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
214 
215         Mockito.doThrow(new RuntimeException()).when(this.httpProcessor).process(
216                 Matchers.any(HttpResponse.class), Matchers.any(HttpContext.class));
217         final HttpException httpex = new HttpException();
218         try {
219             this.protocolHandler.exception(this.conn, httpex);
220             Assert.fail("RuntimeException expected");
221         } catch (final RuntimeException ex) {
222             Mockito.verify(this.conn).shutdown();
223             Mockito.verify(this.requestConsumer).failed(httpex);
224             Mockito.verify(this.requestConsumer, Mockito.atLeastOnce()).close();
225             Mockito.verify(this.responseProducer).failed(httpex);
226             Mockito.verify(this.responseProducer, Mockito.atLeastOnce()).close();
227             Mockito.verify(this.cancellable).cancel();
228         }
229     }
230 
231     @Test
232     public void testHttpExceptionHandlingIOException() throws Exception {
233         final State state = new State();
234         state.setRequestState(MessageState.READY);
235         state.setResponseState(MessageState.READY);
236         final HttpContext exchangeContext = new BasicHttpContext();
237         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
238         final Incoming incoming = new Incoming(
239                 request, this.requestHandler, this.requestConsumer, exchangeContext);
240         state.setIncoming(incoming);
241         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
242         final Outgoing outgoing = new Outgoing(
243                 request, response, this.responseProducer, exchangeContext);
244         state.setOutgoing(outgoing);
245         state.setCancellable(this.cancellable);
246         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
247 
248         Mockito.doThrow(new IOException()).when(this.httpProcessor).process(
249                 Matchers.any(HttpResponse.class), Matchers.any(HttpContext.class));
250         final HttpException httpex = new HttpException();
251 
252         this.protocolHandler.exception(this.conn, httpex);
253 
254         Mockito.verify(this.conn).shutdown();
255         Mockito.verify(this.requestConsumer).failed(httpex);
256         Mockito.verify(this.requestConsumer, Mockito.atLeastOnce()).close();
257         Mockito.verify(this.responseProducer).failed(httpex);
258         Mockito.verify(this.responseProducer, Mockito.atLeastOnce()).close();
259         Mockito.verify(this.cancellable).cancel();
260     }
261 
262     @Test
263     public void testHttpExceptionHandlingResponseSubmitted() throws Exception {
264         final State state = new State();
265         state.setRequestState(MessageState.READY);
266         state.setResponseState(MessageState.READY);
267         final HttpContext exchangeContext = new BasicHttpContext();
268         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
269         final Incoming incoming = new Incoming(
270                 request, this.requestHandler, this.requestConsumer, exchangeContext);
271         state.setIncoming(incoming);
272         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
273         final Outgoing outgoing = new Outgoing(
274                 request, response, this.responseProducer, exchangeContext);
275         state.setOutgoing(outgoing);
276         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
277         Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.TRUE);
278 
279         final HttpException httpex = new HttpException();
280         this.protocolHandler.exception(this.conn, httpex);
281 
282         Assert.assertEquals(MessageState.READY, state.getRequestState());
283         Assert.assertEquals(MessageState.READY, state.getResponseState());
284         Mockito.verify(this.conn).shutdown();
285         Mockito.verify(this.requestConsumer).failed(httpex);
286         Mockito.verify(this.requestConsumer).close();
287         Mockito.verify(this.responseProducer).failed(httpex);
288         Mockito.verify(this.responseProducer).close();
289     }
290 
291     @Test
292     public void testBasicRequest() throws Exception {
293         final State state = new State();
294         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
295 
296         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
297         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
298         Mockito.when(this.requestHandler.processRequest(
299                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
300         Mockito.when(this.requestConsumer.getException()).thenReturn(null);
301         final Object data = new Object();
302         Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
303 
304         this.protocolHandler.requestReceived(this.conn);
305 
306         Assert.assertEquals(MessageState.READY, state.getRequestState());
307         Assert.assertEquals(MessageState.READY, state.getResponseState());
308 
309         final Incoming incoming = state.getIncoming();
310         Assert.assertNull(incoming);
311 
312         final ArgumentCaptor<HttpContext> argumentCaptor = ArgumentCaptor.forClass(HttpContext.class);
313         Mockito.verify(this.httpProcessor).process(Matchers.eq(request), argumentCaptor.capture());
314         final HttpContext exchangeContext = argumentCaptor.getValue();
315         Assert.assertNotNull(exchangeContext);
316 
317         Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
318         Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
319 
320         Mockito.verify(this.requestConsumer).requestReceived(request);
321         Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
322         Mockito.verify(this.conn).requestOutput();
323 
324         final PipelineEntry entry = state.getPipeline().poll();
325         Assert.assertNotNull(entry);
326         Assert.assertSame(request, entry.getRequest());
327         Assert.assertSame(requestHandler, entry.getHandler());
328         Assert.assertNotNull(entry.getResult());
329         Assert.assertNull(entry.getException());
330     }
331 
332     @Test
333     public void testRequestPipelineIfResponseInitiated() throws Exception {
334         final State state = new State();
335         state.setRequestState(MessageState.READY);
336         state.setResponseState(MessageState.INIT);
337         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
338 
339         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
340         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
341         Mockito.when(this.requestHandler.processRequest(
342                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
343         Mockito.when(this.requestConsumer.getException()).thenReturn(null);
344         final Object data = new Object();
345         Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
346 
347         this.protocolHandler.requestReceived(this.conn);
348 
349         Assert.assertEquals(MessageState.READY, state.getRequestState());
350         Assert.assertEquals(MessageState.INIT, state.getResponseState());
351 
352         final Incoming incoming = state.getIncoming();
353         Assert.assertNull(incoming);
354 
355         Mockito.verify(this.requestConsumer).requestReceived(request);
356         Mockito.verify(this.requestConsumer).requestCompleted(Matchers.<HttpContext>any());
357         Mockito.verify(this.requestHandler, Mockito.never()).handle(
358                 Matchers.any(),
359                 Matchers.any(HttpAsyncExchange.class),
360                 Matchers.any(HttpContext.class));
361 
362         Assert.assertFalse(state.getPipeline().isEmpty());
363         final PipelineEntry entry = state.getPipeline().remove();
364         Assert.assertSame(request, entry.getRequest());
365         Assert.assertSame(data, entry.getResult());
366     }
367 
368     @Test
369     public void testRequestPipelineIfPipelineNotEmpty() throws Exception {
370         final State state = new State();
371         state.setRequestState(MessageState.READY);
372         state.setResponseState(MessageState.READY);
373 
374         final Queue<PipelineEntry> pipeline = state.getPipeline();
375 
376         final HttpContext exchangeContext = new BasicHttpContext();
377         final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
378         final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
379                 null, requestHandler, exchangeContext);
380         pipeline.add(entry);
381 
382         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
383 
384         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
385         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
386         Mockito.when(this.requestHandler.processRequest(
387                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
388         Mockito.when(this.requestConsumer.getException()).thenReturn(null);
389         final Object data = new Object();
390         Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
391 
392         this.protocolHandler.requestReceived(this.conn);
393 
394         Assert.assertEquals(MessageState.READY, state.getRequestState());
395         Assert.assertEquals(MessageState.READY, state.getResponseState());
396 
397         final Incoming incoming = state.getIncoming();
398         Assert.assertNull(incoming);
399 
400         Mockito.verify(this.requestConsumer).requestReceived(request);
401         Mockito.verify(this.requestConsumer).requestCompleted(Matchers.<HttpContext>any());
402         Mockito.verify(this.requestHandler, Mockito.never()).handle(
403                 Matchers.any(),
404                 Matchers.any(HttpAsyncExchange.class),
405                 Matchers.any(HttpContext.class));
406 
407         Assert.assertFalse(state.getPipeline().isEmpty());
408         final PipelineEntry entry1 = state.getPipeline().remove();
409         Assert.assertSame(entry, entry1);
410         final PipelineEntry entry2 = state.getPipeline().remove();
411         Assert.assertSame(request, entry2.getRequest());
412         Assert.assertSame(data, entry2.getResult());
413     }
414 
415     @Test
416     public void testRequestNoMatchingHandler() throws Exception {
417         final State state = new State();
418         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
419 
420         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST",
421                 "/stuff", HttpVersion.HTTP_1_1);
422         request.setEntity(new NStringEntity("stuff"));
423         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
424         Mockito.when(this.requestHandler.processRequest(
425                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
426 
427         this.protocolHandler.requestReceived(this.conn);
428 
429         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
430         Assert.assertEquals(MessageState.READY, state.getResponseState());
431 
432         final Incoming incoming = state.getIncoming();
433         Assert.assertNotNull(incoming);
434         Assert.assertSame(request, incoming.getRequest());
435         Assert.assertTrue(incoming.getHandler() instanceof NullRequestHandler);
436     }
437 
438     @Test
439     public void testEntityEnclosingRequest() throws Exception {
440         final State state = new State();
441         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
442 
443         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
444                 HttpVersion.HTTP_1_1);
445         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
446         Mockito.when(this.requestHandler.processRequest(
447                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
448 
449         this.protocolHandler.requestReceived(this.conn);
450 
451         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
452         Assert.assertEquals(MessageState.READY, state.getResponseState());
453 
454         final Incoming incoming = state.getIncoming();
455         Assert.assertNotNull(incoming);
456         Assert.assertSame(request, incoming.getRequest());
457         Assert.assertSame(this.requestHandler, incoming.getHandler());
458         Assert.assertSame(this.requestConsumer, incoming.getConsumer());
459 
460         final HttpContext exchangeContext = incoming.getContext();
461         Assert.assertNotNull(exchangeContext);
462 
463         Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
464         Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
465 
466         Mockito.verify(this.httpProcessor).process(request, exchangeContext);
467         Mockito.verify(this.requestConsumer).requestReceived(request);
468         Mockito.verify(this.conn, Mockito.never()).suspendInput();
469     }
470 
471     @Test
472     public void testEntityEnclosingRequestContinueWithoutVerification() throws Exception {
473         final State state = new State();
474         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
475 
476         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
477                 HttpVersion.HTTP_1_1);
478         request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
479         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
480         Mockito.when(this.requestHandler.processRequest(
481                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
482 
483         this.protocolHandler.requestReceived(this.conn);
484 
485         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
486         Assert.assertEquals(MessageState.READY, state.getResponseState());
487 
488         final Incoming incoming = state.getIncoming();
489         Assert.assertNotNull(incoming);
490         Assert.assertSame(request, incoming.getRequest());
491         Assert.assertSame(this.requestHandler, incoming.getHandler());
492         Assert.assertSame(this.requestConsumer, incoming.getConsumer());
493 
494         final HttpContext exchangeContext = incoming.getContext();
495         Assert.assertNotNull(exchangeContext);
496 
497         Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
498         Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
499 
500         Mockito.verify(this.httpProcessor).process(request, exchangeContext);
501         Mockito.verify(this.requestConsumer).requestReceived(request);
502         Mockito.verify(this.conn, Mockito.never()).suspendInput();
503         Mockito.verify(this.conn).submitResponse(Matchers.argThat(new ArgumentMatcher<HttpResponse>() {
504 
505             @Override
506             public boolean matches(final Object argument) {
507                 final int status = ((HttpResponse) argument).getStatusLine().getStatusCode();
508                 return status == 100;
509             }
510 
511         }));
512     }
513 
514     @Test
515     public void testEntityEnclosingRequestExpectationVerification() throws Exception {
516         final HttpAsyncExpectationVerifier expectationVerifier = Mockito.mock(HttpAsyncExpectationVerifier.class);
517         this.protocolHandler = new HttpAsyncService(
518                 this.httpProcessor, this.reuseStrategy, this.responseFactory,
519                 this.handlerResolver, expectationVerifier);
520 
521         final State state = new State();
522         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
523 
524         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
525                 HttpVersion.HTTP_1_1);
526         request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
527         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
528         Mockito.when(this.requestHandler.processRequest(
529                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
530 
531         this.protocolHandler.requestReceived(this.conn);
532 
533         Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
534         Assert.assertEquals(MessageState.READY, state.getResponseState());
535 
536         final Incoming incoming = state.getIncoming();
537         Assert.assertNotNull(incoming);
538         Assert.assertSame(request, incoming.getRequest());
539         Assert.assertSame(this.requestHandler, incoming.getHandler());
540         Assert.assertSame(this.requestConsumer, incoming.getConsumer());
541 
542         final HttpContext exchangeContext = incoming.getContext();
543         Assert.assertNotNull(exchangeContext);
544 
545         Assert.assertSame(request, exchangeContext.getAttribute(HttpCoreContext.HTTP_REQUEST));
546         Assert.assertSame(this.conn, exchangeContext.getAttribute(HttpCoreContext.HTTP_CONNECTION));
547 
548         Mockito.verify(this.httpProcessor).process(request, exchangeContext);
549         Mockito.verify(this.requestConsumer).requestReceived(request);
550         Mockito.verify(this.conn).suspendInput();
551         Mockito.verify(expectationVerifier).verify(
552                 Matchers.any(HttpAsyncExchange.class),
553                 Matchers.eq(exchangeContext));
554     }
555 
556     @Test
557     public void testRequestExpectationFailed() throws Exception {
558         final State state = new State();
559         state.setRequestState(MessageState.ACK_EXPECTED);
560         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
561 
562         final HttpContext exchangeContext = new BasicHttpContext();
563         final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
564                 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
565                 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
566                 state, this.conn, exchangeContext);
567         Assert.assertFalse(httpexchanage.isCompleted());
568         httpexchanage.submitResponse(this.responseProducer);
569         Assert.assertTrue(httpexchanage.isCompleted());
570 
571         Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
572         Assert.assertEquals(MessageState.READY, state.getResponseState());
573         final Outgoing outgoing = state.getOutgoing();
574         Assert.assertNotNull(outgoing);
575         Assert.assertSame(this.responseProducer, outgoing.getProducer());
576 
577         Mockito.verify(this.conn).requestOutput();
578 
579         try {
580             httpexchanage.submitResponse();
581             Assert.fail("IllegalStateException expected");
582         } catch (final IllegalStateException ex) {
583         }
584     }
585 
586     @Test(expected=IllegalArgumentException.class)
587     public void testRequestExpectationFailedInvalidResponseProducer() throws Exception {
588         final State state = new State();
589         state.setRequestState(MessageState.ACK_EXPECTED);
590         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
591 
592         final HttpContext exchangeContext = new BasicHttpContext();
593         final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
594                 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
595                 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
596                 state, this.conn, exchangeContext);
597         httpexchanage.submitResponse(null);
598     }
599 
600     @Test
601     public void testRequestExpectationNoHandshakeIfResponseInitiated() throws Exception {
602         final State state = new State();
603         state.setRequestState(MessageState.READY);
604         state.setResponseState(MessageState.INIT);
605         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
606 
607         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
608                 HttpVersion.HTTP_1_1);
609         request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
610 
611         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
612         Mockito.when(this.requestHandler.processRequest(
613                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
614 
615         this.protocolHandler.requestReceived(this.conn);
616 
617         Mockito.verify(this.requestConsumer).requestReceived(request);
618 
619         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
620         Assert.assertEquals(MessageState.INIT, state.getResponseState());
621     }
622 
623     @Test
624     public void testRequestExpectationNoHandshakeIfPipelineNotEmpty() throws Exception {
625         final State state = new State();
626         state.setRequestState(MessageState.READY);
627         state.setResponseState(MessageState.READY);
628 
629         final Queue<PipelineEntry> pipeline = state.getPipeline();
630 
631         final HttpContext exchangeContext = new BasicHttpContext();
632         final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
633         final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
634                 null, requestHandler, exchangeContext);
635         pipeline.add(entry);
636 
637         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
638 
639         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
640                 HttpVersion.HTTP_1_1);
641         request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
642 
643         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
644         Mockito.when(this.requestHandler.processRequest(
645                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
646 
647         this.protocolHandler.requestReceived(this.conn);
648 
649         Mockito.verify(this.requestConsumer).requestReceived(request);
650 
651         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
652         Assert.assertEquals(MessageState.READY, state.getResponseState());
653     }
654 
655     @Test
656     public void testRequestExpectationNoHandshakeIfMoreInputAvailable() throws Exception {
657         final State state = new State();
658         state.setRequestState(MessageState.READY);
659         state.setResponseState(MessageState.READY);
660 
661         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
662 
663         this.conn = Mockito.mock(NHttpServerConnection.class,
664                 Mockito.withSettings().extraInterfaces(SessionBufferStatus.class));
665 
666         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
667                 HttpVersion.HTTP_1_1);
668         request.addHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
669 
670         Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
671         Mockito.when(this.conn.getHttpRequest()).thenReturn(request);
672         Mockito.when(this.requestHandler.processRequest(
673                 Matchers.eq(request), Matchers.any(HttpContext.class))).thenReturn(this.requestConsumer);
674         Mockito.when(((SessionBufferStatus) this.conn).hasBufferedInput()).thenReturn(Boolean.TRUE);
675 
676         this.protocolHandler.requestReceived(this.conn);
677 
678         Mockito.verify(this.requestConsumer).requestReceived(request);
679 
680         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
681         Assert.assertEquals(MessageState.READY, state.getResponseState());
682     }
683 
684     @Test
685     public void testRequestContinue() throws Exception {
686         final State state = new State();
687         state.setRequestState(MessageState.ACK_EXPECTED);
688         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
689 
690         final HttpContext exchangeContext = new BasicHttpContext();
691         final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
692                 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
693                 new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue"),
694                 state, this.conn, exchangeContext);
695         Assert.assertFalse(httpexchanage.isCompleted());
696         httpexchanage.submitResponse();
697         Assert.assertTrue(httpexchanage.isCompleted());
698 
699         final Outgoing outgoing = state.getOutgoing();
700         Assert.assertNotNull(outgoing);
701         final HttpAsyncResponseProducer responseProducer = outgoing.getProducer();
702         Assert.assertNotNull(responseProducer);
703         Assert.assertEquals(MessageState.ACK_EXPECTED, state.getRequestState());
704         Assert.assertEquals(MessageState.READY, state.getResponseState());
705         final HttpResponse response = responseProducer.generateResponse();
706         Assert.assertEquals(HttpStatus.SC_CONTINUE, response.getStatusLine().getStatusCode());
707 
708         Mockito.verify(this.conn).requestOutput();
709 
710         try {
711             httpexchanage.submitResponse(this.responseProducer);
712             Assert.fail("IllegalStateException expected");
713         } catch (final IllegalStateException ex) {
714         }
715     }
716 
717     @Test
718     public void testRequestContent() throws Exception {
719         final State state = new State();
720         final HttpContext exchangeContext = new BasicHttpContext();
721         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
722                 HttpVersion.HTTP_1_1);
723         state.setRequestState(MessageState.BODY_STREAM);
724         final Incoming incoming = new Incoming(
725                 request, this.requestHandler, this.requestConsumer, exchangeContext);
726         state.setIncoming(incoming);
727         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
728         Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.FALSE);
729 
730         this.protocolHandler.inputReady(conn, this.decoder);
731 
732         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
733         Assert.assertEquals(MessageState.READY, state.getResponseState());
734 
735         Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
736         Mockito.verify(this.conn, Mockito.never()).suspendInput();
737     }
738 
739     @Test
740     public void testRequestContentCompleted() throws Exception {
741         final State state = new State();
742         final HttpContext exchangeContext = new BasicHttpContext();
743         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
744                 HttpVersion.HTTP_1_1);
745         state.setRequestState(MessageState.BODY_STREAM);
746         final Incoming incoming = new Incoming(
747                 request, this.requestHandler, this.requestConsumer, exchangeContext);
748         state.setIncoming(incoming);
749         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
750         Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.TRUE);
751         Mockito.when(this.requestConsumer.getException()).thenReturn(null);
752         final Object data = new Object();
753         Mockito.when(this.requestConsumer.getResult()).thenReturn(data);
754 
755         this.protocolHandler.inputReady(conn, this.decoder);
756 
757         Assert.assertEquals(MessageState.READY, state.getRequestState());
758         Assert.assertEquals(MessageState.READY, state.getResponseState());
759 
760         Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
761         Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
762         Mockito.verify(this.conn).requestOutput();
763 
764         final PipelineEntry entry = state.getPipeline().poll();
765         Assert.assertNotNull(entry);
766         Assert.assertSame(request, entry.getRequest());
767         Assert.assertSame(requestHandler, entry.getHandler());
768         Assert.assertNotNull(entry.getResult());
769         Assert.assertNull(entry.getException());
770     }
771 
772     @Test
773     public void testRequestCompletedWithException() throws Exception {
774         final State state = new State();
775         final HttpContext exchangeContext = new BasicHttpContext();
776         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
777                 HttpVersion.HTTP_1_1);
778         state.setRequestState(MessageState.BODY_STREAM);
779         final Incoming incoming = new Incoming(
780                 request, this.requestHandler, this.requestConsumer, exchangeContext);
781         state.setIncoming(incoming);
782         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
783         Mockito.when(this.decoder.isCompleted()).thenReturn(Boolean.TRUE);
784         Mockito.when(this.requestConsumer.getException()).thenReturn(new HttpException());
785         Mockito.when(this.requestConsumer.getResult()).thenReturn(null);
786 
787         this.protocolHandler.inputReady(conn, this.decoder);
788 
789         Assert.assertEquals(MessageState.READY, state.getRequestState());
790         Assert.assertEquals(MessageState.READY, state.getResponseState());
791 
792         Mockito.verify(this.requestConsumer).consumeContent(this.decoder, this.conn);
793         Mockito.verify(this.requestConsumer).requestCompleted(exchangeContext);
794         Mockito.verify(this.conn).requestOutput();
795 
796         final PipelineEntry entry = state.getPipeline().poll();
797         Assert.assertNotNull(entry);
798         Assert.assertSame(request, entry.getRequest());
799         Assert.assertSame(requestHandler, entry.getHandler());
800         Assert.assertNull(entry.getResult());
801         Assert.assertNotNull(entry.getException());
802     }
803 
804     @Test
805     public void testBasicResponse() throws Exception {
806         final State state = new State();
807         final HttpContext exchangeContext = new BasicHttpContext();
808         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
809         final Incoming incoming = new Incoming(
810                 request, this.requestHandler, this.requestConsumer, exchangeContext);
811         state.setIncoming(incoming);
812         state.setRequestState(MessageState.COMPLETED);
813         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
814         final Outgoing outgoing = new Outgoing(
815                 request, response, this.responseProducer, exchangeContext);
816         state.setOutgoing(outgoing);
817         state.setResponseState(MessageState.INIT);
818         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
819 
820         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
821         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
822 
823         this.protocolHandler.responseReady(this.conn);
824 
825         Assert.assertEquals(MessageState.READY, state.getResponseState());
826 
827         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
828         Mockito.verify(this.conn).submitResponse(response);
829         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
830         Mockito.verify(this.conn).requestInput();
831         Mockito.verify(this.conn, Mockito.never()).close();
832     }
833 
834     @Test
835     public void testBasicResponseWithPipelining() throws Exception {
836         final State state = new State();
837         final HttpContext exchangeContext = new BasicHttpContext();
838         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
839         final Incoming incoming = new Incoming(
840                 request, this.requestHandler, this.requestConsumer, exchangeContext);
841         state.setIncoming(incoming);
842         state.setRequestState(MessageState.COMPLETED);
843         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
844         final Outgoing outgoing = new Outgoing(
845                 request, response, this.responseProducer, exchangeContext);
846         response.setEntity(new NStringEntity("stuff"));
847         state.setOutgoing(outgoing);
848 
849         final Queue<PipelineEntry> pipeline = state.getPipeline();
850 
851         final HttpContext exchangeContext2 = new BasicHttpContext();
852         final HttpRequest pipelinedRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
853         final PipelineEntry entry = new PipelineEntry(pipelinedRequest, pipelinedRequest,
854                 null, requestHandler, exchangeContext2);
855         pipeline.add(entry);
856 
857         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
858 
859         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
860         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
861 
862         this.protocolHandler.responseReady(this.conn);
863 
864         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
865 
866         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
867         Mockito.verify(this.conn).suspendOutput();
868         Mockito.verify(this.conn).submitResponse(response);
869         Mockito.verify(this.conn, Mockito.never()).close();
870     }
871 
872     @Test
873     public void testBasicResponseNoKeepAlive() throws Exception {
874         final State state = new State();
875         final HttpContext exchangeContext = new BasicHttpContext();
876         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
877         final Incoming incoming = new Incoming(
878                 request, this.requestHandler, this.requestConsumer, exchangeContext);
879         state.setIncoming(incoming);
880         state.setRequestState(MessageState.COMPLETED);
881         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
882         final Outgoing outgoing = new Outgoing(
883                 request, response, this.responseProducer, exchangeContext);
884         state.setOutgoing(outgoing);
885         state.setResponseState(MessageState.INIT);
886         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
887 
888         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
889         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.FALSE);
890 
891         this.protocolHandler.responseReady(this.conn);
892 
893         Assert.assertEquals(MessageState.READY, state.getResponseState());
894 
895         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
896         Mockito.verify(this.conn).submitResponse(response);
897         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
898         Mockito.verify(this.conn).close();
899     }
900 
901     @Test
902     public void testEntityEnclosingResponse() throws Exception {
903         final State state = new State();
904         final HttpContext exchangeContext = new BasicHttpContext();
905         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
906         final Incoming incoming = new Incoming(
907                 request, this.requestHandler, this.requestConsumer, exchangeContext);
908         state.setIncoming(incoming);
909         state.setRequestState(MessageState.COMPLETED);
910         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
911         final Outgoing outgoing = new Outgoing(
912                 request, response, this.responseProducer, exchangeContext);
913         state.setOutgoing(outgoing);
914         state.setResponseState(MessageState.INIT);
915         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
916 
917         response.setEntity(new NStringEntity("stuff"));
918         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
919 
920         this.protocolHandler.responseReady(this.conn);
921 
922         Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
923         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
924         Assert.assertEquals("[incoming COMPLETED GET / HTTP/1.1; outgoing BODY_STREAM HTTP/1.1 200 OK]",
925                 state.toString());
926 
927         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
928         Mockito.verify(this.conn).submitResponse(response);
929         Mockito.verify(this.responseProducer, Mockito.never()).responseCompleted(exchangeContext);
930     }
931 
932     @Test
933     public void testResponseToHead() throws Exception {
934         final State state = new State();
935         final HttpContext exchangeContext = new BasicHttpContext();
936         final HttpRequest request = new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1);
937         final Incoming incoming = new Incoming(
938                 request, this.requestHandler, this.requestConsumer, exchangeContext);
939         state.setIncoming(incoming);
940         state.setRequestState(MessageState.COMPLETED);
941         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
942         final Outgoing outgoing = new Outgoing(
943                 request, response, this.responseProducer, exchangeContext);
944         state.setOutgoing(outgoing);
945         state.setResponseState(MessageState.INIT);
946         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
947 
948         response.setEntity(new NStringEntity("stuff"));
949         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
950         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
951 
952         this.protocolHandler.responseReady(this.conn);
953 
954         Assert.assertEquals(MessageState.READY, state.getResponseState());
955 
956         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
957         Mockito.verify(this.conn).submitResponse(response);
958         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
959         Mockito.verify(this.conn).requestInput();
960         Mockito.verify(this.conn, Mockito.never()).close();
961     }
962 
963     @Test
964     public void testResponseNotModified() throws Exception {
965         final State state = new State();
966         final HttpContext exchangeContext = new BasicHttpContext();
967         final HttpRequest request = new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1);
968         final Incoming incoming = new Incoming(
969                 request, this.requestHandler, this.requestConsumer, exchangeContext);
970         state.setIncoming(incoming);
971         state.setRequestState(MessageState.COMPLETED);
972         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
973                 HttpStatus.SC_NOT_MODIFIED, "Not modified");
974         final Outgoing outgoing = new Outgoing(
975                 request, response, this.responseProducer, exchangeContext);
976         state.setOutgoing(outgoing);
977         state.setResponseState(MessageState.INIT);
978         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
979 
980         response.setEntity(new NStringEntity("stuff"));
981         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
982         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
983 
984         this.protocolHandler.responseReady(this.conn);
985 
986         Assert.assertEquals(MessageState.READY, state.getResponseState());
987 
988         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
989         Mockito.verify(this.conn).submitResponse(response);
990         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
991         Mockito.verify(this.conn).requestInput();
992         Mockito.verify(this.conn, Mockito.never()).close();
993     }
994 
995     @Test
996     public void testResponseContinue() throws Exception {
997         final State state = new State();
998         final HttpContext exchangeContext = new BasicHttpContext();
999         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1000                 HttpVersion.HTTP_1_1);
1001         final Incoming incoming = new Incoming(
1002                 request, this.requestHandler, this.requestConsumer, exchangeContext);
1003         state.setIncoming(incoming);
1004         state.setRequestState(MessageState.ACK_EXPECTED);
1005         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
1006                 HttpStatus.SC_CONTINUE, "Continue");
1007         final Outgoing outgoing = new Outgoing(
1008                 request, response, this.responseProducer, exchangeContext);
1009         state.setOutgoing(outgoing);
1010         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1011 
1012         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1013 
1014         this.protocolHandler.responseReady(this.conn);
1015 
1016         Assert.assertEquals(MessageState.BODY_STREAM, state.getRequestState());
1017         Assert.assertEquals(MessageState.READY, state.getResponseState());
1018 
1019         Mockito.verify(this.conn).requestInput();
1020         Mockito.verify(this.conn).submitResponse(Matchers.argThat(new ArgumentMatcher<HttpResponse>() {
1021 
1022             @Override
1023             public boolean matches(final Object argument) {
1024                 final int status = ((HttpResponse) argument).getStatusLine().getStatusCode();
1025                 return status == 100;
1026             }
1027 
1028         }));
1029     }
1030 
1031     @Test
1032     public void testResponseFailedExpectation() throws Exception {
1033         final State state = new State();
1034         final HttpContext exchangeContext = new BasicHttpContext();
1035         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1036                 HttpVersion.HTTP_1_1);
1037         final Incoming incoming = new Incoming(
1038                 request, this.requestHandler, this.requestConsumer, exchangeContext);
1039         state.setIncoming(incoming);
1040         state.setRequestState(MessageState.ACK_EXPECTED);
1041         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
1042                 417, "Expectation failed");
1043         final Outgoing outgoing = new Outgoing(
1044                 request, response, this.responseProducer, exchangeContext);
1045         state.setOutgoing(outgoing);
1046         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1047 
1048         response.setEntity(new NStringEntity("stuff"));
1049         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1050 
1051         this.protocolHandler.responseReady(this.conn);
1052 
1053         Assert.assertEquals(MessageState.READY, state.getRequestState());
1054         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1055 
1056         Mockito.verify(this.conn).resetInput();
1057         Mockito.verify(this.httpProcessor).process(response, exchangeContext);
1058         Mockito.verify(this.conn).submitResponse(response);
1059         Mockito.verify(this.responseProducer, Mockito.never()).responseCompleted(exchangeContext);
1060     }
1061 
1062     @Test
1063     public void testResponsePipelinedEmpty() throws Exception {
1064         final State state = new State();
1065 
1066         state.setRequestState(MessageState.READY);
1067         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1068 
1069         this.protocolHandler.responseReady(this.conn);
1070 
1071         Assert.assertEquals(MessageState.READY, state.getRequestState());
1072         Assert.assertEquals(MessageState.READY, state.getResponseState());
1073         Assert.assertNull(state.getOutgoing());
1074 
1075         Mockito.verify(conn).suspendOutput();
1076         Mockito.verifyNoMoreInteractions(requestHandler);
1077     }
1078 
1079     @Test
1080     public void testResponseHandlePipelinedRequest() throws Exception {
1081         final State state = new State();
1082         final Queue<PipelineEntry> pipeline = state.getPipeline();
1083 
1084         final HttpContext exchangeContext = new BasicHttpContext();
1085         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1086         final PipelineEntry entry = new PipelineEntry(request, request, null, requestHandler, exchangeContext);
1087         pipeline.add(entry);
1088 
1089         state.setRequestState(MessageState.READY);
1090         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1091 
1092         this.protocolHandler.responseReady(this.conn);
1093 
1094         Assert.assertEquals(MessageState.READY, state.getRequestState());
1095         Assert.assertEquals(MessageState.INIT, state.getResponseState());
1096         Assert.assertNull(state.getOutgoing());
1097 
1098         final ArgumentCaptor<HttpAsyncExchange> argCaptor = ArgumentCaptor.forClass(HttpAsyncExchange.class);
1099         Mockito.verify(this.requestHandler).handle(Matchers.same(request),
1100                 argCaptor.capture(), Matchers.same(exchangeContext));
1101         final HttpAsyncExchange exchange = argCaptor.getValue();
1102 
1103         Assert.assertNotNull(exchange);
1104         Assert.assertSame(request, exchange.getRequest());
1105         Assert.assertNotNull(exchange.getResponse());
1106         Assert.assertEquals(200, exchange.getResponse().getStatusLine().getStatusCode());
1107     }
1108 
1109     @Test
1110     public void testResponseHandleFailedPipelinedRequest() throws Exception {
1111         final State state = new State();
1112         final Queue<PipelineEntry> pipeline = state.getPipeline();
1113 
1114         final HttpContext exchangeContext = new BasicHttpContext();
1115         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1116         final Exception ex = new Exception("Opppsie");
1117         final PipelineEntry entry = new PipelineEntry(request, null, ex, requestHandler, exchangeContext);
1118         pipeline.add(entry);
1119 
1120         state.setRequestState(MessageState.READY);
1121         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1122 
1123         this.protocolHandler.responseReady(this.conn);
1124 
1125         Assert.assertEquals(MessageState.READY, state.getRequestState());
1126         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1127 
1128         final Outgoing outgoing = state.getOutgoing();
1129         Assert.assertNotNull(outgoing.getProducer());
1130         final HttpResponse response = outgoing.getResponse();
1131         Assert.assertNotNull(response);
1132         Assert.assertEquals(500, response.getStatusLine().getStatusCode());
1133 
1134         Mockito.verify(this.requestHandler, Mockito.never()).handle(Matchers.<HttpRequest>any(),
1135                 Matchers.<HttpAsyncExchange>any(), Matchers.<HttpContext>any());
1136         Mockito.verify(this.conn).submitResponse(Matchers.same(response));
1137     }
1138 
1139     @Test(expected=HttpException.class)
1140     public void testInvalidResponseStatus() throws Exception {
1141         final State state = new State();
1142         final HttpContext exchangeContext = new BasicHttpContext();
1143         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1144                 HttpVersion.HTTP_1_1);
1145         final Incoming incoming = new Incoming(
1146                 request, this.requestHandler, this.requestConsumer, exchangeContext);
1147         state.setIncoming(incoming);
1148         state.setRequestState(MessageState.COMPLETED);
1149         state.setResponseState(MessageState.INIT);
1150         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 112, "Something stupid");
1151         final Outgoing outgoing = new Outgoing(
1152                 request, response, this.responseProducer, exchangeContext);
1153         state.setOutgoing(outgoing);
1154         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1155 
1156         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1157         Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.FALSE);
1158 
1159         this.protocolHandler.responseReady(this.conn);
1160     }
1161 
1162     @Test(expected=HttpException.class)
1163     public void testInvalidResponseStatusToExpection() throws Exception {
1164         final State state = new State();
1165         final HttpContext exchangeContext = new BasicHttpContext();
1166         final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/",
1167                 HttpVersion.HTTP_1_1);
1168         final Incoming incoming = new Incoming(
1169                 request, this.requestHandler, this.requestConsumer, exchangeContext);
1170         state.setIncoming(incoming);
1171         state.setRequestState(MessageState.ACK_EXPECTED);
1172         state.setResponseState(MessageState.READY);
1173         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1174         response.setEntity(new NStringEntity("stuff"));
1175         final Outgoing outgoing = new Outgoing(
1176                 request, response, this.responseProducer, exchangeContext);
1177         state.setOutgoing(outgoing);
1178         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1179 
1180         Mockito.when(this.responseProducer.generateResponse()).thenReturn(response);
1181         Mockito.when(this.conn.isResponseSubmitted()).thenReturn(Boolean.FALSE);
1182 
1183         this.protocolHandler.responseReady(this.conn);
1184     }
1185 
1186     @Test
1187     public void testResponseTrigger() throws Exception {
1188         final State state = new State();
1189         state.setRequestState(MessageState.COMPLETED);
1190         state.setResponseState(MessageState.READY);
1191         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1192 
1193         final HttpContext exchangeContext = new BasicHttpContext();
1194         final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
1195                 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
1196                 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
1197                 state, this.conn, exchangeContext);
1198         Assert.assertFalse(httpexchanage.isCompleted());
1199         httpexchanage.submitResponse(this.responseProducer);
1200         Assert.assertTrue(httpexchanage.isCompleted());
1201 
1202         Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
1203         Assert.assertEquals(MessageState.READY, state.getResponseState());
1204         final Outgoing outgoing = state.getOutgoing();
1205         Assert.assertNotNull(outgoing);
1206         Assert.assertSame(this.responseProducer, outgoing.getProducer());
1207 
1208         Mockito.verify(this.conn).requestOutput();
1209 
1210         try {
1211             httpexchanage.submitResponse(Mockito.mock(HttpAsyncResponseProducer.class));
1212             Assert.fail("IllegalStateException expected");
1213         } catch (final IllegalStateException ex) {
1214         }
1215     }
1216 
1217     @Test(expected=IllegalArgumentException.class)
1218     public void testResponseTriggerInvalidResponseProducer() throws Exception {
1219         final State state = new State();
1220         state.setRequestState(MessageState.ACK_EXPECTED);
1221         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1222 
1223         final HttpContext exchangeContext = new BasicHttpContext();
1224         final HttpAsyncExchange httpexchanage = protocolHandler.new HttpAsyncExchangeImpl(
1225                 new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1),
1226                 new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"),
1227                 state, this.conn, exchangeContext);
1228         httpexchanage.submitResponse(null);
1229     }
1230 
1231     @Test
1232     public void testResponseContent() throws Exception {
1233         final State state = new State();
1234         state.setRequestState(MessageState.COMPLETED);
1235         state.setResponseState(MessageState.BODY_STREAM);
1236         final HttpContext exchangeContext = new BasicHttpContext();
1237         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1238         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1239         response.setEntity(new NStringEntity("stuff"));
1240         final Outgoing outgoing = new Outgoing(
1241                 request, response, this.responseProducer, exchangeContext);
1242         state.setOutgoing(outgoing);
1243         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1244         Mockito.when(this.encoder.isCompleted()).thenReturn(Boolean.FALSE);
1245 
1246         this.protocolHandler.outputReady(conn, this.encoder);
1247 
1248         Assert.assertEquals(MessageState.COMPLETED, state.getRequestState());
1249         Assert.assertEquals(MessageState.BODY_STREAM, state.getResponseState());
1250 
1251         Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1252         Mockito.verify(this.conn, Mockito.never()).requestInput();
1253         Mockito.verify(this.conn, Mockito.never()).close();
1254     }
1255 
1256     @Test
1257     public void testResponseContentCompleted() throws Exception {
1258         final State state = new State();
1259         state.setRequestState(MessageState.COMPLETED);
1260         state.setResponseState(MessageState.BODY_STREAM);
1261         final HttpContext exchangeContext = new BasicHttpContext();
1262         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1263         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1264         response.setEntity(new NStringEntity("stuff"));
1265         final Outgoing outgoing = new Outgoing(
1266                 request, response, this.responseProducer, exchangeContext);
1267         state.setOutgoing(outgoing);
1268         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1269         Mockito.when(this.encoder.isCompleted()).thenReturn(true);
1270         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.TRUE);
1271 
1272         this.protocolHandler.outputReady(conn, this.encoder);
1273 
1274         Assert.assertEquals(MessageState.READY, state.getResponseState());
1275 
1276         Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1277         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
1278         Mockito.verify(this.conn).requestInput();
1279         Mockito.verify(this.conn, Mockito.never()).close();
1280     }
1281 
1282     @Test
1283     public void testResponseContentCompletedNoKeepAlive() throws Exception {
1284         final State state = new State();
1285         state.setRequestState(MessageState.COMPLETED);
1286         state.setResponseState(MessageState.BODY_STREAM);
1287         final HttpContext exchangeContext = new BasicHttpContext();
1288         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1289         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1290         response.setEntity(new NStringEntity("stuff"));
1291         final Outgoing outgoing = new Outgoing(
1292                 request, response, this.responseProducer, exchangeContext);
1293         state.setOutgoing(outgoing);
1294         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1295         Mockito.when(this.encoder.isCompleted()).thenReturn(true);
1296         Mockito.when(this.reuseStrategy.keepAlive(response, exchangeContext)).thenReturn(Boolean.FALSE);
1297 
1298         this.protocolHandler.outputReady(conn, this.encoder);
1299 
1300         Assert.assertEquals(MessageState.READY, state.getResponseState());
1301 
1302         Mockito.verify(this.responseProducer).produceContent(this.encoder, this.conn);
1303         Mockito.verify(this.responseProducer).responseCompleted(exchangeContext);
1304         Mockito.verify(this.conn, Mockito.never()).requestInput();
1305         Mockito.verify(this.conn).close();
1306     }
1307 
1308     @Test
1309     public void testEndOfInput() throws Exception {
1310 
1311         Mockito.when(this.conn.getSocketTimeout()).thenReturn(1000);
1312 
1313         this.protocolHandler.endOfInput(this.conn);
1314 
1315         Mockito.verify(this.conn, Mockito.never()).setSocketTimeout(Matchers.anyInt());
1316         Mockito.verify(this.conn).close();
1317     }
1318 
1319     @Test
1320     public void testEndOfInputNoTimeout() throws Exception {
1321 
1322         Mockito.when(this.conn.getSocketTimeout()).thenReturn(0);
1323 
1324         this.protocolHandler.endOfInput(this.conn);
1325 
1326         Mockito.verify(this.conn).setSocketTimeout(1000);
1327         Mockito.verify(this.conn).close();
1328     }
1329 
1330     @Test
1331     public void testTimeoutActiveConnection() throws Exception {
1332         final State state = new State();
1333         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1334         Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSED);
1335 
1336         this.protocolHandler.timeout(this.conn);
1337 
1338         Mockito.verify(this.conn).close();
1339         Mockito.verify(this.conn, Mockito.never()).setSocketTimeout(Matchers.anyInt());
1340     }
1341 
1342     @Test
1343     public void testTimeoutActiveConnectionBufferedData() throws Exception {
1344         final State state = new State();
1345         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1346         Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSING);
1347 
1348         this.protocolHandler.timeout(this.conn);
1349 
1350         Mockito.verify(this.conn).close();
1351         Mockito.verify(this.conn).setSocketTimeout(250);
1352     }
1353 
1354     @Test
1355     public void testTimeoutClosingConnection() throws Exception {
1356         final State state = new State();
1357         final HttpContext exchangeContext = new BasicHttpContext();
1358         final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
1359         final Incoming incoming = new Incoming(
1360                 request, this.requestHandler, this.requestConsumer, exchangeContext);
1361         state.setIncoming(incoming);
1362         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
1363         final Outgoing outgoing = new Outgoing(
1364                 request, response, this.responseProducer, exchangeContext);
1365         state.setOutgoing(outgoing);
1366         this.connContext.setAttribute(HttpAsyncService.HTTP_EXCHANGE_STATE, state);
1367         Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.CLOSING);
1368 
1369         this.protocolHandler.timeout(this.conn);
1370 
1371         Mockito.verify(this.conn).shutdown();
1372         Mockito.verify(this.requestConsumer).failed(Matchers.any(SocketTimeoutException.class));
1373         Mockito.verify(this.requestConsumer).close();
1374         Mockito.verify(this.responseProducer).failed(Matchers.any(SocketTimeoutException.class));
1375         Mockito.verify(this.responseProducer).close();
1376     }
1377 
1378 }