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), ResponseType.WHOLE);
95          WriteRequest rwr = new DefaultWriteRequest(req);
96  
97          // Record
98          nextFilter.filterWrite(session, new DefaultWriteRequest(req.getMessage()));
99          nextFilterControl.setMatcher(matcher);
100         nextFilter.messageSent(session, rwr);
101         nextFilter.messageReceived(session, res);
102 
103         // Replay
104         nextFilterControl.replay();
105         filter.filterWrite(nextFilter, session, rwr);
106         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
107         filter.messageReceived(nextFilter, session, res.getMessage());
108         filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
109 
110         // Verify
111         nextFilterControl.verify();
112         assertEquals(res, req.awaitResponse());
113         assertNoSuchElementException(req);
114     }
115 
116     private void assertNoSuchElementException(Request req) throws InterruptedException {
117         // Make sure if an exception is thrown if a user waits one more time.
118         try {
119             req.awaitResponse();
120             fail();
121         } catch (NoSuchElementException e) {
122             // Signifies a successful test execution
123             assertTrue(true);
124         }
125     }
126 
127     @Test
128     public void testPartialResponse() throws Exception {
129         Request req = new Request(1, new Object(), Long.MAX_VALUE);
130         Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL), ResponseType.PARTIAL);
131         Response res2 = new Response(req, new Message(1, ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
132         WriteRequest rwr = new DefaultWriteRequest(req);
133 
134         // Record
135         nextFilter.filterWrite(session, new DefaultWriteRequest(req.getMessage()));
136         nextFilterControl.setMatcher(matcher);
137         nextFilter.messageSent(session, rwr);
138         nextFilter.messageReceived(session, res1);
139         nextFilter.messageReceived(session, res2);
140 
141         // Replay
142         nextFilterControl.replay();
143         filter.filterWrite(nextFilter, session, rwr);
144         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
145         filter.messageReceived(nextFilter, session, res1.getMessage());
146         filter.messageReceived(nextFilter, session, res2.getMessage());
147         filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
148         filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
149 
150         // Verify
151         nextFilterControl.verify();
152         assertEquals(res1, req.awaitResponse());
153         assertEquals(res2, req.awaitResponse());
154         assertNoSuchElementException(req);
155     }
156 
157     @Test
158     public void testWholeResponseTimeout() throws Exception {
159         Request req = new Request(1, new Object(), 10); // 10ms timeout
160         Response res = new Response(req, new Message(1, ResponseType.WHOLE), ResponseType.WHOLE);
161         WriteRequest rwr = new DefaultWriteRequest(req);
162 
163         // Record
164         nextFilter.filterWrite(session, new DefaultWriteRequest(req.getMessage()));
165         nextFilterControl.setMatcher(matcher);
166         nextFilter.messageSent(session, rwr);
167         nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
168         nextFilterControl.setMatcher(new ExceptionMatcher());
169 
170         // Replay
171         nextFilterControl.replay();
172         filter.filterWrite(nextFilter, session, rwr);
173         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
174         Thread.sleep(300); // Wait until the request times out.
175         filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
176 
177         // Verify
178         nextFilterControl.verify();
179         assertRequestTimeoutException(req);
180         assertNoSuchElementException(req);
181     }
182 
183     private void assertRequestTimeoutException(Request req) throws InterruptedException {
184         try {
185             req.awaitResponse();
186             fail();
187         } catch (RequestTimeoutException e) {
188             // Signifies a successful test execution
189             assertTrue(true);
190         }
191     }
192 
193     @Test
194     public void testPartialResponseTimeout() throws Exception {
195         Request req = new Request(1, new Object(), 10); // 10ms timeout
196         Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL), ResponseType.PARTIAL);
197         Response res2 = new Response(req, new Message(1, ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
198         WriteRequest rwr = new DefaultWriteRequest(req);
199 
200         // Record
201         nextFilter.filterWrite(session, new DefaultWriteRequest(req.getMessage()));
202         nextFilterControl.setMatcher(matcher);
203         nextFilter.messageSent(session, rwr);
204         nextFilter.messageReceived(session, res1);
205         nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
206         nextFilterControl.setMatcher(new ExceptionMatcher());
207 
208         // Replay
209         nextFilterControl.replay();
210         filter.filterWrite(nextFilter, session, rwr);
211         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
212         filter.messageReceived(nextFilter, session, res1.getMessage());
213         Thread.sleep(300); // Wait until the request times out.
214         filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
215         filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
216 
217         // Verify
218         nextFilterControl.verify();
219         assertEquals(res1, req.awaitResponse());
220         assertRequestTimeoutException(req);
221         assertNoSuchElementException(req);
222     }
223 
224     @Test
225     public void testTimeoutByDisconnection() throws Exception {
226         // We run a test case that doesn't raise a timeout to make sure
227         // the timeout is not raised again by disconnection.
228         testWholeResponse();
229         nextFilterControl.reset();
230 
231         Request req1 = new Request(1, new Object(), Long.MAX_VALUE);
232         Request req2 = new Request(2, new Object(), Long.MAX_VALUE);
233         WriteRequest rwr1 = new DefaultWriteRequest(req1);
234         WriteRequest rwr2 = new DefaultWriteRequest(req2);
235 
236         // Record
237         nextFilter.filterWrite(session, new DefaultWriteRequest(req1.getMessage()));
238         nextFilterControl.setMatcher(matcher);
239         nextFilter.messageSent(session, rwr1);
240         nextFilter.filterWrite(session, new DefaultWriteRequest(req2.getMessage()));
241         nextFilter.messageSent(session, rwr2);
242         nextFilter.exceptionCaught(session, new RequestTimeoutException(req1));
243         nextFilterControl.setMatcher(new ExceptionMatcher());
244         nextFilter.exceptionCaught(session, new RequestTimeoutException(req2));
245         nextFilter.sessionClosed(session);
246 
247         // Replay
248         nextFilterControl.replay();
249         filter.filterWrite(nextFilter, session, rwr1);
250         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
251         filter.filterWrite(nextFilter, session, rwr2);
252         filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
253         filter.sessionClosed(nextFilter, session);
254 
255         // Verify
256         nextFilterControl.verify();
257         assertRequestTimeoutException(req1);
258         assertRequestTimeoutException(req2);
259     }
260 
261     static class Message {
262         private final int id;
263 
264         private final ResponseType type;
265 
266         Message(int id, ResponseType type) {
267             this.id = id;
268             this.type = type;
269         }
270 
271         public int getId() {
272             return id;
273         }
274 
275         public ResponseType getType() {
276             return type;
277         }
278     }
279 
280     private static class MessageInspector implements ResponseInspector {
281         /**
282          * Default constructor
283          */
284         public MessageInspector() {
285             super();
286         }
287 
288         public Object getRequestId(Object message) {
289             if (!(message instanceof Message)) {
290                 return null;
291             }
292 
293             return ((Message) message).getId();
294         }
295 
296         public ResponseType getResponseType(Object message) {
297             if (!(message instanceof Message)) {
298                 return null;
299             }
300 
301             return ((Message) message).getType();
302         }
303     }
304 
305     private static class WriteRequestMatcher extends AbstractMatcher {
306         private WriteRequest lastWriteRequest;
307 
308         /**
309          * Default constructor
310          */
311         public WriteRequestMatcher() {
312             super();
313         }
314 
315         public WriteRequest getLastWriteRequest() {
316             return lastWriteRequest;
317         }
318 
319         @Override
320         protected boolean argumentMatches(Object expected, Object actual) {
321             if (actual instanceof WriteRequest && expected instanceof WriteRequest) {
322                 boolean answer = ((WriteRequest) expected).getMessage().equals(((WriteRequest) actual).getMessage());
323                 lastWriteRequest = (WriteRequest) actual;
324                 return answer;
325             }
326             return super.argumentMatches(expected, actual);
327         }
328     }
329 
330     static class ExceptionMatcher extends AbstractMatcher {
331         @Override
332         protected boolean argumentMatches(Object expected, Object actual) {
333             if (actual instanceof RequestTimeoutException && expected instanceof RequestTimeoutException) {
334                 return ((RequestTimeoutException) expected).getRequest().equals(
335                         ((RequestTimeoutException) actual).getRequest());
336             }
337             return super.argumentMatches(expected, actual);
338         }
339     }
340 }