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   * @version $Rev: 713957 $, $Date: 2008-11-14 10:27:16 +0100 (Fri, 14 Nov 2008) $
44   */
45  public abstract class AbstractConnectorTest extends TestCase {
46  
47      protected abstract IoAcceptor createAcceptor();
48      protected abstract IoConnector createConnector();
49  
50      public void testConnectFutureSuccessTiming() throws Exception {
51          int port = AvailablePortFinder.getNextAvailable(2025);
52          IoAcceptor acceptor = createAcceptor();
53          acceptor.setHandler(new IoHandlerAdapter());
54          acceptor.bind(new InetSocketAddress(port));
55  
56          try {
57              final StringBuffer buf = new StringBuffer();
58              IoConnector connector = createConnector();
59              connector.setHandler(new IoHandlerAdapter() {
60                  @Override
61                  public void sessionCreated(IoSession session) {
62                      buf.append("1");
63                  }
64  
65                  @Override
66                  public void sessionOpened(IoSession session) {
67                      buf.append("2");
68                  }
69  
70                  @Override
71                  public void exceptionCaught(IoSession session, Throwable cause) {
72                      buf.append("X");
73                  }
74              });
75              ConnectFuture future = connector.connect(new InetSocketAddress(
76                      "localhost", port));
77              future.awaitUninterruptibly();
78              buf.append("3");
79              future.getSession().close(true);
80              // sessionCreated() will fire before the connect future completes
81              // but sessionOpened() may not
82              Assert.assertTrue(Pattern.matches("12?32?", buf.toString()));
83          } finally {
84              acceptor.dispose();
85          }
86      }
87  
88      public void testConnectFutureFailureTiming() throws Exception {
89          int port = AvailablePortFinder.getNextAvailable(3025);
90          final StringBuffer buf = new StringBuffer();
91  
92          IoConnector connector = createConnector();
93          connector.setHandler(new IoHandlerAdapter() {
94              @Override
95              public void sessionCreated(IoSession session) {
96                  buf.append("X");
97              }
98  
99              @Override
100             public void sessionOpened(IoSession session) {
101                 buf.append("Y");
102             }
103 
104             @Override
105             public void exceptionCaught(IoSession session, Throwable cause) {
106                 buf.append("Z");
107             }
108         });
109         
110         try {
111             ConnectFuture future = connector.connect(new InetSocketAddress(
112                     "localhost", port));
113             future.awaitUninterruptibly();
114             buf.append("1");
115             try {
116                 future.getSession().close(true);
117                 fail();
118             } catch (RuntimeIoException e) {
119                 // OK.
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 }