1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.testsuite.transport.socket;
17
18 import io.netty5.bootstrap.Bootstrap;
19 import io.netty5.bootstrap.ServerBootstrap;
20 import io.netty5.buffer.api.Buffer;
21 import io.netty5.buffer.api.DefaultBufferAllocators;
22 import io.netty5.channel.Channel;
23 import io.netty5.channel.ChannelHandler;
24 import io.netty5.channel.ChannelHandlerAdapter;
25 import io.netty5.channel.ChannelHandlerContext;
26 import io.netty5.channel.ChannelShutdownDirection;
27 import io.netty5.channel.SingleThreadEventLoop;
28 import io.netty5.channel.nio.NioHandler;
29 import io.netty5.channel.socket.SocketChannel;
30 import io.netty5.channel.socket.nio.NioServerSocketChannel;
31 import io.netty5.handler.codec.ByteToMessageDecoder;
32 import io.netty5.util.concurrent.DefaultThreadFactory;
33 import org.junit.jupiter.api.Test;
34 import org.junit.jupiter.api.TestInfo;
35 import org.junit.jupiter.api.Timeout;
36
37 import java.nio.channels.NotYetConnectedException;
38 import java.util.concurrent.CountDownLatch;
39
40 import static org.assertj.core.api.Assertions.assertThat;
41 import static org.junit.jupiter.api.Assertions.assertFalse;
42 import static org.junit.jupiter.api.Assertions.fail;
43
44 public class SocketChannelNotYetConnectedTest extends AbstractClientSocketTest {
45 @Test
46 @Timeout(30)
47 public void testShutdownNotYetConnected(TestInfo testInfo) throws Throwable {
48 run(testInfo, this::testShutdownNotYetConnected);
49 }
50
51 public void testShutdownNotYetConnected(Bootstrap cb) throws Throwable {
52 SocketChannel ch = (SocketChannel) cb.handler(new ChannelHandler() { })
53 .bind(newSocketAddress()).asStage().get();
54 try {
55 try {
56 ch.shutdown(ChannelShutdownDirection.Inbound).asStage().sync();
57 fail();
58 } catch (Throwable cause) {
59 assertThat(cause).hasCauseInstanceOf(NotYetConnectedException.class);
60 }
61
62 try {
63 ch.shutdown(ChannelShutdownDirection.Outbound).asStage().sync();
64 fail();
65 } catch (Throwable cause) {
66 assertThat(cause).hasCauseInstanceOf(NotYetConnectedException.class);
67 }
68 } finally {
69 ch.close().asStage().sync();
70 }
71 }
72
73 @Test
74 @Timeout(30)
75 public void readMustBePendingUntilChannelIsActive(TestInfo info) throws Throwable {
76 run(info, new Runner<>() {
77 @Override
78 public void run(Bootstrap bootstrap) throws Throwable {
79 SingleThreadEventLoop group = new SingleThreadEventLoop(
80 new DefaultThreadFactory(getClass()), NioHandler.newFactory().newHandler());
81 ServerBootstrap sb = new ServerBootstrap().group(group);
82 Channel serverChannel = sb.childHandler(new ChannelHandlerAdapter() {
83 @Override
84 public void channelActive(ChannelHandlerContext ctx) throws Exception {
85 ctx.writeAndFlush(DefaultBufferAllocators.preferredAllocator().allocate(4).writeInt(42));
86 }
87 }).channel(NioServerSocketChannel.class).bind(0).asStage().get();
88
89 final CountDownLatch readLatch = new CountDownLatch(1);
90 bootstrap.handler(new ByteToMessageDecoder() {
91 @Override
92 public void handlerAdded0(ChannelHandlerContext ctx) throws Exception {
93 assertFalse(ctx.channel().isActive());
94 ctx.read();
95 }
96
97 @Override
98 protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception {
99 assertThat(in.readableBytes()).isLessThanOrEqualTo(Integer.BYTES);
100 if (in.readableBytes() == Integer.BYTES) {
101 assertThat(in.readInt()).isEqualTo(42);
102 readLatch.countDown();
103 }
104 }
105 });
106 bootstrap.connect(serverChannel.localAddress()).asStage().sync();
107
108 readLatch.await();
109 group.shutdownGracefully().asStage().await();
110 }
111 });
112 }
113 }