/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.mina.filter.reqres;
import java.util.NoSuchElementException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import junit.framework.TestCase;
import org.apache.mina.core.filterchain.IoFilterChain;
import org.apache.mina.core.filterchain.IoFilter.NextFilter;
import org.apache.mina.core.session.DummySession;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.DefaultWriteRequest;
import org.apache.mina.core.write.WriteRequest;
import org.easymock.AbstractMatcher;
import org.easymock.MockControl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Tests {@link RequestResponseFilter}.
*
* @author The Apache MINA Project (dev@mina.apache.org)
* @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $
*/
public class RequestResponseFilterTest extends TestCase {
private ScheduledExecutorService scheduler;
private RequestResponseFilter filter;
private IoSession session;
private IoFilterChain chain;
private NextFilter nextFilter;
private MockControl nextFilterControl;
private final WriteRequestMatcher matcher = new WriteRequestMatcher();
@Override
@Before
public void setUp() throws Exception {
scheduler = Executors.newScheduledThreadPool(1);
filter = new RequestResponseFilter(new MessageInspector(), scheduler);
// Set up mock objects.
session = new DummySession();
chain = session.getFilterChain();
nextFilterControl = MockControl.createControl(NextFilter.class);
nextFilter = (NextFilter) nextFilterControl.getMock();
// Initialize the filter.
filter.onPreAdd(chain, "reqres", nextFilter);
filter.onPostAdd(chain, "reqres", nextFilter);
Assert.assertFalse(session.getAttributeKeys().isEmpty());
}
@Override
@After
public void tearDown() throws Exception {
// Destroy the filter.
filter.onPreRemove(chain, "reqres", nextFilter);
filter.onPostRemove(chain, "reqres", nextFilter);
filter.destroy();
filter = null;
scheduler.shutdown();
}
@Test
public void testWholeResponse() throws Exception {
Request req = new Request(1, new Object(), Long.MAX_VALUE);
Response res = new Response(req, new Message(1, ResponseType.WHOLE),
ResponseType.WHOLE);
WriteRequest rwr = new DefaultWriteRequest(req);
// Record
nextFilter.filterWrite(session, new DefaultWriteRequest(req
.getMessage()));
nextFilterControl.setMatcher(matcher);
nextFilter.messageSent(session, rwr);
nextFilter.messageReceived(session, res);
// Replay
nextFilterControl.replay();
filter.filterWrite(nextFilter, session, rwr);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
filter.messageReceived(nextFilter, session, res.getMessage());
filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
// Verify
nextFilterControl.verify();
Assert.assertEquals(res, req.awaitResponse());
assertNoSuchElementException(req);
}
private void assertNoSuchElementException(Request req)
throws InterruptedException {
// Make sure if an exception is thrown if a user waits one more time.
try {
req.awaitResponse();
Assert.fail();
} catch (NoSuchElementException e) {
// OK
}
}
@Test
public void testPartialResponse() throws Exception {
Request req = new Request(1, new Object(), Long.MAX_VALUE);
Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL),
ResponseType.PARTIAL);
Response res2 = new Response(req, new Message(1,
ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
WriteRequest rwr = new DefaultWriteRequest(req);
// Record
nextFilter.filterWrite(session, new DefaultWriteRequest(req
.getMessage()));
nextFilterControl.setMatcher(matcher);
nextFilter.messageSent(session, rwr);
nextFilter.messageReceived(session, res1);
nextFilter.messageReceived(session, res2);
// Replay
nextFilterControl.replay();
filter.filterWrite(nextFilter, session, rwr);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
filter.messageReceived(nextFilter, session, res1.getMessage());
filter.messageReceived(nextFilter, session, res2.getMessage());
filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
// Verify
nextFilterControl.verify();
Assert.assertEquals(res1, req.awaitResponse());
Assert.assertEquals(res2, req.awaitResponse());
assertNoSuchElementException(req);
}
@Test
public void testWholeResponseTimeout() throws Exception {
Request req = new Request(1, new Object(), 10); // 10ms timeout
Response res = new Response(req, new Message(1, ResponseType.WHOLE),
ResponseType.WHOLE);
WriteRequest rwr = new DefaultWriteRequest(req);
// Record
nextFilter.filterWrite(session, new DefaultWriteRequest(req
.getMessage()));
nextFilterControl.setMatcher(matcher);
nextFilter.messageSent(session, rwr);
nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
nextFilterControl.setMatcher(new ExceptionMatcher());
// Replay
nextFilterControl.replay();
filter.filterWrite(nextFilter, session, rwr);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
Thread.sleep(300); // Wait until the request times out.
filter.messageReceived(nextFilter, session, res.getMessage()); // Ignored
// Verify
nextFilterControl.verify();
assertRequestTimeoutException(req);
assertNoSuchElementException(req);
}
private void assertRequestTimeoutException(Request req)
throws InterruptedException {
try {
req.awaitResponse();
Assert.fail();
} catch (RequestTimeoutException e) {
// OK
}
}
@Test
public void testPartialResponseTimeout() throws Exception {
Request req = new Request(1, new Object(), 10); // 10ms timeout
Response res1 = new Response(req, new Message(1, ResponseType.PARTIAL),
ResponseType.PARTIAL);
Response res2 = new Response(req, new Message(1,
ResponseType.PARTIAL_LAST), ResponseType.PARTIAL_LAST);
WriteRequest rwr = new DefaultWriteRequest(req);
// Record
nextFilter.filterWrite(session, new DefaultWriteRequest(req
.getMessage()));
nextFilterControl.setMatcher(matcher);
nextFilter.messageSent(session, rwr);
nextFilter.messageReceived(session, res1);
nextFilter.exceptionCaught(session, new RequestTimeoutException(req));
nextFilterControl.setMatcher(new ExceptionMatcher());
// Replay
nextFilterControl.replay();
filter.filterWrite(nextFilter, session, rwr);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
filter.messageReceived(nextFilter, session, res1.getMessage());
Thread.sleep(300); // Wait until the request times out.
filter.messageReceived(nextFilter, session, res2.getMessage()); // Ignored
filter.messageReceived(nextFilter, session, res1.getMessage()); // Ignored
// Verify
nextFilterControl.verify();
Assert.assertEquals(res1, req.awaitResponse());
assertRequestTimeoutException(req);
assertNoSuchElementException(req);
}
@Test
public void testTimeoutByDisconnection() throws Exception {
// We run a test case that doesn't raise a timeout to make sure
// the timeout is not raised again by disconnection.
testWholeResponse();
nextFilterControl.reset();
Request req1 = new Request(1, new Object(), Long.MAX_VALUE);
Request req2 = new Request(2, new Object(), Long.MAX_VALUE);
WriteRequest rwr1 = new DefaultWriteRequest(req1);
WriteRequest rwr2 = new DefaultWriteRequest(req2);
// Record
nextFilter.filterWrite(session, new DefaultWriteRequest(req1
.getMessage()));
nextFilterControl.setMatcher(matcher);
nextFilter.messageSent(session, rwr1);
nextFilter.filterWrite(session, new DefaultWriteRequest(req2
.getMessage()));
nextFilter.messageSent(session, rwr2);
nextFilter.exceptionCaught(session, new RequestTimeoutException(req1));
nextFilterControl.setMatcher(new ExceptionMatcher());
nextFilter.exceptionCaught(session, new RequestTimeoutException(req2));
nextFilter.sessionClosed(session);
// Replay
nextFilterControl.replay();
filter.filterWrite(nextFilter, session, rwr1);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
filter.filterWrite(nextFilter, session, rwr2);
filter.messageSent(nextFilter, session, matcher.getLastWriteRequest());
filter.sessionClosed(nextFilter, session);
// Verify
nextFilterControl.verify();
assertRequestTimeoutException(req1);
assertRequestTimeoutException(req2);
}
private static class Message {
private final int id;
private final ResponseType type;
private Message(int id, ResponseType type) {
this.id = id;
this.type = type;
}
public int getId() {
return id;
}
public ResponseType getType() {
return type;
}
}
private static class MessageInspector implements ResponseInspector {
public Object getRequestId(Object message) {
if (!(message instanceof Message)) {
return null;
}
return ((Message) message).getId();
}
public ResponseType getResponseType(Object message) {
if (!(message instanceof Message)) {
return null;
}
return ((Message) message).getType();
}
}
private static class WriteRequestMatcher extends AbstractMatcher {
private WriteRequest lastWriteRequest;
public WriteRequest getLastWriteRequest() {
return lastWriteRequest;
}
@Override
protected boolean argumentMatches(Object expected, Object actual) {
if (actual instanceof WriteRequest
&& expected instanceof WriteRequest) {
boolean answer = ((WriteRequest) expected).getMessage().equals(
((WriteRequest) actual).getMessage());
lastWriteRequest = (WriteRequest) actual;
return answer;
}
return super.argumentMatches(expected, actual);
}
}
private static class ExceptionMatcher extends AbstractMatcher {
@Override
protected boolean argumentMatches(Object expected, Object actual) {
if (actual instanceof RequestTimeoutException
&& expected instanceof RequestTimeoutException) {
return ((RequestTimeoutException) expected)
.getRequest()
.equals(((RequestTimeoutException) actual).getRequest());
}
return super.argumentMatches(expected, actual);
}
}
}