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}