001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.transport; 021 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertSame; 025import static org.junit.Assert.assertTrue; 026import static org.junit.Assert.fail; 027 028import java.net.InetSocketAddress; 029import java.util.concurrent.CountDownLatch; 030import java.util.concurrent.TimeUnit; 031import java.util.regex.Pattern; 032 033import org.apache.mina.core.RuntimeIoException; 034import org.apache.mina.core.future.ConnectFuture; 035import org.apache.mina.core.service.IoAcceptor; 036import org.apache.mina.core.service.IoConnector; 037import org.apache.mina.core.service.IoHandlerAdapter; 038import org.apache.mina.core.session.IoSession; 039import org.apache.mina.core.session.IoSessionInitializer; 040import org.apache.mina.util.AvailablePortFinder; 041import org.junit.Test; 042 043/** 044 * Tests a generic {@link IoConnector}. 045 * 046 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 047 */ 048public abstract class AbstractConnectorTest { 049 050 protected abstract IoAcceptor createAcceptor(); 051 052 protected abstract IoConnector createConnector(); 053 054 @Test 055 public void testConnectFutureSuccessTiming() throws Exception { 056 int port = AvailablePortFinder.getNextAvailable(1025); 057 IoAcceptor acceptor = createAcceptor(); 058 acceptor.setHandler(new IoHandlerAdapter()); 059 acceptor.bind(new InetSocketAddress(port)); 060 061 try { 062 final StringBuffer buf = new StringBuffer(); 063 IoConnector connector = createConnector(); 064 connector.setHandler(new IoHandlerAdapter() { 065 @Override 066 public void sessionCreated(IoSession session) { 067 buf.append("1"); 068 } 069 070 @Override 071 public void sessionOpened(IoSession session) { 072 buf.append("2"); 073 } 074 075 @Override 076 public void exceptionCaught(IoSession session, Throwable cause) { 077 buf.append("X"); 078 } 079 }); 080 ConnectFuture future = connector.connect(new InetSocketAddress("localhost", port)); 081 future.awaitUninterruptibly(); 082 buf.append("3"); 083 future.getSession().close(true); 084 // sessionCreated() will fire before the connect future completes 085 // but sessionOpened() may not 086 assertTrue(Pattern.matches("12?32?", buf.toString())); 087 } finally { 088 acceptor.dispose(); 089 } 090 } 091 092 @Test 093 public void testConnectFutureFailureTiming() throws Exception { 094 int port = AvailablePortFinder.getNextAvailable(1025); 095 final StringBuffer buf = new StringBuffer(); 096 097 IoConnector connector = createConnector(); 098 connector.setHandler(new IoHandlerAdapter() { 099 @Override 100 public void sessionCreated(IoSession session) { 101 buf.append("X"); 102 } 103 104 @Override 105 public void sessionOpened(IoSession session) { 106 buf.append("Y"); 107 } 108 109 @Override 110 public void exceptionCaught(IoSession session, Throwable cause) { 111 buf.append("Z"); 112 } 113 }); 114 115 try { 116 ConnectFuture future = connector.connect(new InetSocketAddress("localhost", port)); 117 future.awaitUninterruptibly(); 118 buf.append("1"); 119 try { 120 future.getSession().close(true); 121 fail(); 122 } catch (RuntimeIoException e) { 123 // Signifies a successful test execution 124 assertTrue(true); 125 } 126 assertEquals("1", buf.toString()); 127 } finally { 128 connector.dispose(); 129 } 130 } 131 132 /** 133 * Test to make sure the SessionCallback gets invoked before IoHandler.sessionCreated. 134 */ 135 @Test 136 public void testSessionCallbackInvocation() throws Exception { 137 final int callbackInvoked = 0; 138 final int sessionCreatedInvoked = 1; 139 final int sessionCreatedInvokedBeforeCallback = 2; 140 final boolean[] assertions = { false, false, false }; 141 final CountDownLatch latch = new CountDownLatch(2); 142 final ConnectFuture[] callbackFuture = new ConnectFuture[1]; 143 144 int port = AvailablePortFinder.getNextAvailable(1025); 145 146 IoAcceptor acceptor = createAcceptor(); 147 IoConnector connector = createConnector(); 148 149 try { 150 acceptor.setHandler(new IoHandlerAdapter()); 151 InetSocketAddress address = new InetSocketAddress(port); 152 acceptor.bind(address); 153 154 connector.setHandler(new IoHandlerAdapter() { 155 @Override 156 public void sessionCreated(IoSession session) throws Exception { 157 assertions[sessionCreatedInvoked] = true; 158 assertions[sessionCreatedInvokedBeforeCallback] = !assertions[callbackInvoked]; 159 latch.countDown(); 160 } 161 }); 162 163 ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", port), 164 new IoSessionInitializer<ConnectFuture>() { 165 public void initializeSession(IoSession session, ConnectFuture future) { 166 assertions[callbackInvoked] = true; 167 callbackFuture[0] = future; 168 latch.countDown(); 169 } 170 }); 171 172 assertTrue("Timed out waiting for callback and IoHandler.sessionCreated to be invoked", 173 latch.await(5, TimeUnit.SECONDS)); 174 assertTrue("Callback was not invoked", assertions[callbackInvoked]); 175 assertTrue("IoHandler.sessionCreated was not invoked", assertions[sessionCreatedInvoked]); 176 assertFalse("IoHandler.sessionCreated was invoked before session callback", 177 assertions[sessionCreatedInvokedBeforeCallback]); 178 assertSame("Callback future should have been same future as returned by connect", future, callbackFuture[0]); 179 } finally { 180 try { 181 connector.dispose(); 182 } finally { 183 acceptor.dispose(); 184 } 185 } 186 } 187}