View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.filter.reqres;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.util.NoSuchElementException;
28  import java.util.concurrent.Executors;
29  import java.util.concurrent.ScheduledExecutorService;
30  
31  import org.apache.mina.core.filterchain.IoFilterChain;
32  import org.apache.mina.core.filterchain.IoFilter.NextFilter;
33  import org.apache.mina.core.session.DummySession;
34  import org.apache.mina.core.session.IoSession;
35  import org.apache.mina.core.write.DefaultWriteRequest;
36  import org.apache.mina.core.write.WriteRequest;
37  import org.easymock.AbstractMatcher;
38  import org.easymock.MockControl;
39  import org.junit.After;
40  import org.junit.Before;
41  import org.junit.Test;
42  
43  /**
44   * Tests {@link RequestResponseFilter}.
45   *
46   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
47   */
48  public class RequestResponseFilterTest {
49  
50      private ScheduledExecutorService scheduler;
51  
52      private RequestResponseFilter filter;
53  
54      private IoSession session;
55  
56      private IoFilterChain chain;
57  
58      private NextFilter nextFilter;
59  
60      private MockControl nextFilterControl;
61  
62      private final WriteRequestMatcher matcher = new WriteRequestMatcher();
63  
64      @Before
65      public void setUp() throws Exception {
66          scheduler = Executors.newScheduledThreadPool(1);
67          filter = new RequestResponseFilter(new MessageInspector(), scheduler);
68  
69          // Set up mock objects.
70          session = new DummySession();
71          chain = session.getFilterChain();
72          nextFilterControl = MockControl.createControl(NextFilter.class);
73          nextFilter = (NextFilter) nextFilterControl.getMock();
74  
75          // Initialize the filter.
76          filter.onPreAdd(chain, "reqres", nextFilter);
77          filter.onPostAdd(chain, "reqres", nextFilter);
78          assertFalse(session.getAttributeKeys().isEmpty());
79      }
80  
81      @After
82      public void tearDown() throws Exception {
83          // Destroy the filter.
84          filter.onPreRemove(chain, "reqres", nextFilter);
85          filter.onPostRemove(chain, "reqres", nextFilter);
86          filter.destroy();
87          filter = null;
88          scheduler.shutdown();
89      }
90  
91      @Test
92      public void testWholeResponse() throws Exception {
93          Request req = new Request(1, new Object(), Long.MAX_VALUE);
94          Response res = new Response(req, new Message(1, ResponseType.WHOLE),
95                  ResponseType.WHOLE);
96          WriteRequest rwr = new DefaultWriteRequest(req);
97  
98          // Record
99          nextFilter.filterWrite(session, new DefaultWriteRequest(req
100                 .getMessage()));
101         nextFilterControl.setMatcher(matcher);
102         nextFilter.messageSent(session, rwr);
103         nextFilter.messageReceived(session, res);
104 
105         // Replay
106         nextFilterControl.replay();
107         filter.filterWrite(nextFilter, session, rwr);
108         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
109         filter.messageReceived(nextFilter, session, res.getMessage());
110         filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
111 
112         // Verify
113         nextFilterControl.verify();
114         assertEquals(res, req.awaitResponse());
115         assertNoSuchElementException(req);
116     }
117 
118     private void assertNoSuchElementException(Request req)
119             throws InterruptedException {
120         // Make sure if an exception is thrown if a user waits one more time.
121         try {
122             req.awaitResponse();
123             fail();
124         } catch (NoSuchElementException e) {
125             // Signifies a successful test execution
126             assertTrue(true);
127         }
128     }
129 
130     @Test
131     public void testPartialResponse() throws Exception {
132         Request req = new Request(1, new Object(), Long.MAX_VALUE);
133         Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL),
134                 ResponseType.PARTIAL);
135         Response res2 = new Response(req, new Message(1,
136                 ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
137         WriteRequest rwr = new DefaultWriteRequest(req);
138 
139         // Record
140         nextFilter.filterWrite(session, new DefaultWriteRequest(req
141                 .getMessage()));
142         nextFilterControl.setMatcher(matcher);
143         nextFilter.messageSent(session, rwr);
144         nextFilter.messageReceived(session, res1);
145         nextFilter.messageReceived(session, res2);
146 
147         // Replay
148         nextFilterControl.replay();
149         filter.filterWrite(nextFilter, session, rwr);
150         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
151         filter.messageReceived(nextFilter, session, res1.getMessage());
152         filter.messageReceived(nextFilter, session, res2.getMessage());
153         filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
154         filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
155 
156         // Verify
157         nextFilterControl.verify();
158         assertEquals(res1, req.awaitResponse());
159         assertEquals(res2, req.awaitResponse());
160         assertNoSuchElementException(req);
161     }
162 
163     @Test
164     public void testWholeResponseTimeout() throws Exception {
165         Request req = new Request(1, new Object(), 10); // 10ms timeout
166         Response res = new Response(req, new Message(1, ResponseType.WHOLE),
167                 ResponseType.WHOLE);
168         WriteRequest rwr = new DefaultWriteRequest(req);
169 
170         // Record
171         nextFilter.filterWrite(session, new DefaultWriteRequest(req
172                 .getMessage()));
173         nextFilterControl.setMatcher(matcher);
174         nextFilter.messageSent(session, rwr);
175         nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
176         nextFilterControl.setMatcher(new ExceptionMatcher());
177 
178         // Replay
179         nextFilterControl.replay();
180         filter.filterWrite(nextFilter, session, rwr);
181         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
182         Thread.sleep(300); // Wait until the request times out.
183         filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
184 
185         // Verify
186         nextFilterControl.verify();
187         assertRequestTimeoutException(req);
188         assertNoSuchElementException(req);
189     }
190 
191     private void assertRequestTimeoutException(Request req)
192             throws InterruptedException {
193         try {
194             req.awaitResponse();
195             fail();
196         } catch (RequestTimeoutException e) {
197             // Signifies a successful test execution
198             assertTrue(true);
199         }
200     }
201 
202     @Test
203     public void testPartialResponseTimeout() throws Exception {
204         Request req = new Request(1, new Object(), 10); // 10ms timeout
205         Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL),
206                 ResponseType.PARTIAL);
207         Response res2 = new Response(req, new Message(1,
208                 ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
209         WriteRequest rwr = new DefaultWriteRequest(req);
210 
211         // Record
212         nextFilter.filterWrite(session, new DefaultWriteRequest(req
213                 .getMessage()));
214         nextFilterControl.setMatcher(matcher);
215         nextFilter.messageSent(session, rwr);
216         nextFilter.messageReceived(session, res1);
217         nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
218         nextFilterControl.setMatcher(new ExceptionMatcher());
219 
220         // Replay
221         nextFilterControl.replay();
222         filter.filterWrite(nextFilter, session, rwr);
223         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
224         filter.messageReceived(nextFilter, session, res1.getMessage());
225         Thread.sleep(300); // Wait until the request times out.
226         filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
227         filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
228 
229         // Verify
230         nextFilterControl.verify();
231         assertEquals(res1, req.awaitResponse());
232         assertRequestTimeoutException(req);
233         assertNoSuchElementException(req);
234     }
235 
236     @Test
237     public void testTimeoutByDisconnection() throws Exception {
238         // We run a test case that doesn't raise a timeout to make sure
239         // the timeout is not raised again by disconnection.
240         testWholeResponse();
241         nextFilterControl.reset();
242 
243         Request req1 = new Request(1, new Object(), Long.MAX_VALUE);
244         Request req2 = new Request(2, new Object(), Long.MAX_VALUE);
245         WriteRequest rwr1 = new DefaultWriteRequest(req1);
246         WriteRequest rwr2 = new DefaultWriteRequest(req2);
247 
248         // Record
249         nextFilter.filterWrite(session, new DefaultWriteRequest(req1
250                 .getMessage()));
251         nextFilterControl.setMatcher(matcher);
252         nextFilter.messageSent(session, rwr1);
253         nextFilter.filterWrite(session, new DefaultWriteRequest(req2
254                 .getMessage()));
255         nextFilter.messageSent(session, rwr2);
256         nextFilter.exceptionCaught(session, new RequestTimeoutException(req1));
257         nextFilterControl.setMatcher(new ExceptionMatcher());
258         nextFilter.exceptionCaught(session, new RequestTimeoutException(req2));
259         nextFilter.sessionClosed(session);
260 
261         // Replay
262         nextFilterControl.replay();
263         filter.filterWrite(nextFilter, session, rwr1);
264         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
265         filter.filterWrite(nextFilter, session, rwr2);
266         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
267         filter.sessionClosed(nextFilter, session);
268 
269         // Verify
270         nextFilterControl.verify();
271         assertRequestTimeoutException(req1);
272         assertRequestTimeoutException(req2);
273     }
274 
275     static class Message {
276         private final int id;
277 
278         private final ResponseType type;
279 
280         Message(int id, ResponseType type) {
281             this.id = id;
282             this.type = type;
283         }
284 
285         public int getId() {
286             return id;
287         }
288 
289         public ResponseType getType() {
290             return type;
291         }
292     }
293 
294     private static class MessageInspector implements ResponseInspector {
295         /**
296          * Default constructor
297          */
298         public MessageInspector() {
299             super();
300         }
301         
302         public Object getRequestId(Object message) {
303             if (!(message instanceof Message)) {
304                 return null;
305             }
306 
307             return ((Message) message).getId();
308         }
309 
310         public ResponseType getResponseType(Object message) {
311             if (!(message instanceof Message)) {
312                 return null;
313             }
314 
315             return ((Message) message).getType();
316         }
317     }
318 
319     private static class WriteRequestMatcher extends AbstractMatcher {
320         private WriteRequest lastWriteRequest;
321 
322         /**
323          * Default constructor
324          */
325         public WriteRequestMatcher() {
326             super();
327         }
328         
329         public WriteRequest getLastWriteRequest() {
330             return lastWriteRequest;
331         }
332 
333         @Override
334         protected boolean argumentMatches(Object expected, Object actual) {
335             if (actual instanceof WriteRequest
336                     && expected instanceof WriteRequest) {
337                 boolean answer = ((WriteRequest) expected).getMessage().equals(
338                         ((WriteRequest) actual).getMessage());
339                 lastWriteRequest = (WriteRequest) actual;
340                 return answer;
341             }
342             return super.argumentMatches(expected, actual);
343         }
344     }
345 
346     static class ExceptionMatcher extends AbstractMatcher {
347         @Override
348         protected boolean argumentMatches(Object expected, Object actual) {
349             if (actual instanceof RequestTimeoutException
350                     && expected instanceof RequestTimeoutException) {
351                 return ((RequestTimeoutException) expected)
352                         .getRequest()
353                         .equals(((RequestTimeoutException) actual).getRequest());
354             }
355             return super.argumentMatches(expected, actual);
356         }
357     }
358 }