1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.testsuite.transport.socket;
17
18 import io.netty.bootstrap.Bootstrap;
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelHandler;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.channel.ChannelInboundHandlerAdapter;
24 import io.netty.channel.ChannelOption;
25 import io.netty.channel.socket.oio.OioSocketChannel;
26 import io.netty.util.internal.SocketUtils;
27 import io.netty.util.NetUtil;
28 import io.netty.util.concurrent.GlobalEventExecutor;
29 import io.netty.util.concurrent.Promise;
30 import io.netty.util.internal.logging.InternalLoggerFactory;
31 import org.junit.jupiter.api.Test;
32 import org.junit.jupiter.api.TestInfo;
33 import org.junit.jupiter.api.Timeout;
34
35 import java.io.IOException;
36 import java.net.ConnectException;
37 import java.net.Socket;
38 import java.util.concurrent.TimeUnit;
39
40 import static io.netty.testsuite.transport.socket.SocketTestPermutation.BAD_HOST;
41 import static io.netty.testsuite.transport.socket.SocketTestPermutation.BAD_PORT;
42 import static io.netty.testsuite.transport.socket.SocketTestPermutation.UNASSIGNED_PORT;
43 import static org.junit.jupiter.api.Assertions.assertFalse;
44 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
45 import static org.junit.jupiter.api.Assertions.assertNull;
46 import static org.junit.jupiter.api.Assertions.assertTrue;
47 import static org.junit.jupiter.api.Assertions.fail;
48 import static org.junit.jupiter.api.Assumptions.assumeTrue;
49
50 public class SocketConnectionAttemptTest extends AbstractClientSocketTest {
51
52 @Test
53 @Timeout(value = 30000, unit = TimeUnit.MILLISECONDS)
54 public void testConnectTimeout(TestInfo testInfo) throws Throwable {
55 run(testInfo, new Runner<Bootstrap>() {
56 @Override
57 public void run(Bootstrap bootstrap) throws Throwable {
58 testConnectTimeout(bootstrap);
59 }
60 });
61 }
62
63 public void testConnectTimeout(Bootstrap cb) throws Throwable {
64 cb.handler(new TestHandler()).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000);
65 ChannelFuture future = cb.connect(BAD_HOST, BAD_PORT);
66 try {
67 assertTrue(future.await(3000));
68 } finally {
69 future.channel().close();
70 }
71 }
72
73 @Test
74 @Timeout(value = 30000, unit = TimeUnit.MILLISECONDS)
75 public void testConnectRefused(TestInfo testInfo) throws Throwable {
76 run(testInfo, new Runner<Bootstrap>() {
77 @Override
78 public void run(Bootstrap bootstrap) throws Throwable {
79 testConnectRefused(bootstrap);
80 }
81 });
82 }
83
84 public void testConnectRefused(Bootstrap cb) throws Throwable {
85 testConnectRefused0(cb, false);
86 }
87
88 @Test
89 @Timeout(value = 30000, unit = TimeUnit.MILLISECONDS)
90 public void testConnectRefusedHalfClosure(TestInfo testInfo) throws Throwable {
91 run(testInfo, new Runner<Bootstrap>() {
92 @Override
93 public void run(Bootstrap bootstrap) throws Throwable {
94 testConnectRefusedHalfClosure(bootstrap);
95 }
96 });
97 }
98
99 public void testConnectRefusedHalfClosure(Bootstrap cb) throws Throwable {
100 testConnectRefused0(cb, true);
101 }
102
103 private static void testConnectRefused0(Bootstrap cb, boolean halfClosure) throws Throwable {
104 final Promise<Error> errorPromise = GlobalEventExecutor.INSTANCE.newPromise();
105 ChannelHandler handler = new ChannelInboundHandlerAdapter() {
106 @Override
107 public void channelActive(ChannelHandlerContext ctx) throws Exception {
108 errorPromise.setFailure(new AssertionError("should have never been called"));
109 }
110 };
111
112 cb.handler(handler);
113 cb.option(ChannelOption.ALLOW_HALF_CLOSURE, halfClosure);
114 ChannelFuture future = cb.connect(NetUtil.LOCALHOST, UNASSIGNED_PORT).awaitUninterruptibly();
115 assertInstanceOf(ConnectException.class, future.cause());
116 assertNull(errorPromise.cause());
117 }
118
119 @Test
120 public void testConnectCancellation(TestInfo testInfo) throws Throwable {
121
122
123 boolean badHostTimedOut = true;
124 Socket socket = new Socket();
125 try {
126 SocketUtils.connect(socket, SocketUtils.socketAddress(BAD_HOST, BAD_PORT), 10);
127 } catch (ConnectException e) {
128 badHostTimedOut = false;
129
130 } catch (Exception e) {
131
132 } finally {
133 try {
134 socket.close();
135 } catch (IOException e) {
136
137 }
138 }
139
140 assumeTrue(badHostTimedOut, "The connection attempt to " + BAD_HOST + " does not time out.");
141
142 run(testInfo, new Runner<Bootstrap>() {
143 @Override
144 public void run(Bootstrap bootstrap) throws Throwable {
145 testConnectCancellation(bootstrap);
146 }
147 });
148 }
149
150 public void testConnectCancellation(Bootstrap cb) throws Throwable {
151 cb.handler(new TestHandler()).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4000);
152 ChannelFuture future = cb.connect(BAD_HOST, BAD_PORT);
153 try {
154 if (future.await(1000)) {
155 if (future.isSuccess()) {
156 fail("A connection attempt to " + BAD_HOST + " must not succeed.");
157 } else {
158 throw future.cause();
159 }
160 }
161
162 if (future.cancel(true)) {
163 assertTrue(future.channel().closeFuture().await(500));
164 assertTrue(future.isCancelled());
165 } else {
166
167 assertFalse(isConnectCancellationSupported(future.channel()), future.channel().getClass() +
168 " should support connect cancellation");
169 }
170 } finally {
171 future.channel().close();
172 }
173 }
174
175 @SuppressWarnings("deprecation")
176 protected boolean isConnectCancellationSupported(Channel channel) {
177 return !(channel instanceof OioSocketChannel);
178 }
179
180 private static class TestHandler extends ChannelInboundHandlerAdapter {
181 @Override
182 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
183 InternalLoggerFactory.getInstance(
184 SocketConnectionAttemptTest.class).warn("Unexpected exception:", cause);
185 }
186 }
187 }