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.transport;
21  
22  import java.net.InetSocketAddress;
23  import java.util.concurrent.CountDownLatch;
24  import java.util.concurrent.TimeUnit;
25  import java.util.regex.Pattern;
26  
27  import junit.framework.Assert;
28  import junit.framework.TestCase;
29  
30  import org.apache.mina.core.RuntimeIoException;
31  import org.apache.mina.core.future.ConnectFuture;
32  import org.apache.mina.core.service.IoAcceptor;
33  import org.apache.mina.core.service.IoConnector;
34  import org.apache.mina.core.service.IoHandlerAdapter;
35  import org.apache.mina.core.session.IoSession;
36  import org.apache.mina.core.session.IoSessionInitializer;
37  import org.apache.mina.util.AvailablePortFinder;
38  
39  /**
40   * Tests a generic {@link IoConnector}.
41   *
42   * @author The Apache MINA Project (dev@mina.apache.org)
43   */
44  public abstract class AbstractConnectorTest extends TestCase {
45  
46      protected abstract IoAcceptor createAcceptor();
47      protected abstract IoConnector createConnector();
48  
49      public void testConnectFutureSuccessTiming() throws Exception {
50          int port = AvailablePortFinder.getNextAvailable(2025);
51          IoAcceptor acceptor = createAcceptor();
52          acceptor.setHandler(new IoHandlerAdapter());
53          acceptor.bind(new InetSocketAddress(port));
54  
55          try {
56              final StringBuffer buf = new StringBuffer();
57              IoConnector connector = createConnector();
58              connector.setHandler(new IoHandlerAdapter() {
59                  @Override
60                  public void sessionCreated(IoSession session) {
61                      buf.append("1");
62                  }
63  
64                  @Override
65                  public void sessionOpened(IoSession session) {
66                      buf.append("2");
67                  }
68  
69                  @Override
70                  public void exceptionCaught(IoSession session, Throwable cause) {
71                      buf.append("X");
72                  }
73              });
74              ConnectFuture future = connector.connect(new InetSocketAddress(
75                      "localhost", port));
76              future.awaitUninterruptibly();
77              buf.append("3");
78              future.getSession().close(true);
79              // sessionCreated() will fire before the connect future completes
80              // but sessionOpened() may not
81              Assert.assertTrue(Pattern.matches("12?32?", buf.toString()));
82          } finally {
83              acceptor.dispose();
84          }
85      }
86  
87      public void testConnectFutureFailureTiming() throws Exception {
88          int port = AvailablePortFinder.getNextAvailable(3025);
89          final StringBuffer buf = new StringBuffer();
90  
91          IoConnector connector = createConnector();
92          connector.setHandler(new IoHandlerAdapter() {
93              @Override
94              public void sessionCreated(IoSession session) {
95                  buf.append("X");
96              }
97  
98              @Override
99              public void sessionOpened(IoSession session) {
100                 buf.append("Y");
101             }
102 
103             @Override
104             public void exceptionCaught(IoSession session, Throwable cause) {
105                 buf.append("Z");
106             }
107         });
108         
109         try {
110             ConnectFuture future = connector.connect(new InetSocketAddress(
111                     "localhost", port));
112             future.awaitUninterruptibly();
113             buf.append("1");
114             try {
115                 future.getSession().close(true);
116                 fail();
117             } catch (RuntimeIoException e) {
118                 // Signifies a successful test execution
119                 assertTrue(true);
120             }
121             Assert.assertEquals("1", buf.toString());
122         } finally {
123             connector.dispose();
124         }
125     }
126     
127     /**
128      * Test to make sure the SessionCallback gets invoked before IoHandler.sessionCreated.
129      */
130     public void testSessionCallbackInvocation() throws Exception {
131         final int callbackInvoked = 0;
132         final int sessionCreatedInvoked = 1;
133         final int sessionCreatedInvokedBeforeCallback = 2;
134         final boolean[] assertions = {false, false, false};
135         final CountDownLatch latch = new CountDownLatch(2);
136         final ConnectFuture[] callbackFuture = new ConnectFuture[1];
137         
138         int port = AvailablePortFinder.getNextAvailable(4025);
139         IoAcceptor acceptor = createAcceptor();
140         acceptor.setHandler(new IoHandlerAdapter());
141         InetSocketAddress address = new InetSocketAddress(port);
142         acceptor.bind(address);
143 
144         IoConnector connector = createConnector();
145         connector.setHandler(new IoHandlerAdapter() {
146            @Override
147             public void sessionCreated(IoSession session) throws Exception {
148                    assertions[sessionCreatedInvoked] = true;
149                    assertions[sessionCreatedInvokedBeforeCallback] = !assertions[callbackInvoked];
150                    latch.countDown();
151             } 
152         });
153         
154         ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", port), new IoSessionInitializer<ConnectFuture>() {
155             public void initializeSession(IoSession session, ConnectFuture future) {
156                 assertions[callbackInvoked] = true;
157                 callbackFuture[0] = future;
158                 latch.countDown();
159             }
160         });
161         
162         assertTrue("Timed out waiting for callback and IoHandler.sessionCreated to be invoked", latch.await(5, TimeUnit.SECONDS));
163         assertTrue("Callback was not invoked", assertions[callbackInvoked]);
164         assertTrue("IoHandler.sessionCreated was not invoked", assertions[sessionCreatedInvoked]);
165         assertFalse("IoHandler.sessionCreated was invoked before session callback", assertions[sessionCreatedInvokedBeforeCallback]);
166         assertSame("Callback future should have been same future as returned by connect", future, callbackFuture[0]);
167     }
168 }