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.channel.Channel;
21 import io.netty5.channel.ChannelHandler;
22 import io.netty5.channel.ChannelHandlerContext;
23 import io.netty5.channel.ChannelInitializer;
24 import io.netty5.channel.ChannelOption;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.TestInfo;
27 import org.junit.jupiter.api.Timeout;
28
29 import java.io.IOException;
30 import java.util.Locale;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicReference;
34
35 import static org.junit.jupiter.api.Assertions.assertNull;
36 import static org.junit.jupiter.api.Assertions.assertTrue;
37
38 public class SocketRstTest extends AbstractSocketTest {
39 protected void assertRstOnCloseException(IOException cause, Channel clientChannel) {
40 if (Locale.getDefault() == Locale.US || Locale.getDefault() == Locale.UK) {
41 assertTrue(cause.getMessage().contains("reset") || cause.getMessage().contains("closed"),
42 "actual message: " + cause.getMessage());
43 }
44 }
45
46 @Test
47 @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
48 public void testSoLingerZeroCausesOnlyRstOnClose(TestInfo testInfo) throws Throwable {
49 run(testInfo, this::testSoLingerZeroCausesOnlyRstOnClose);
50 }
51
52 public void testSoLingerZeroCausesOnlyRstOnClose(ServerBootstrap sb, Bootstrap cb) throws Throwable {
53 final AtomicReference<Channel> serverChannelRef = new AtomicReference<>();
54 final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
55 final CountDownLatch latch = new CountDownLatch(1);
56 final CountDownLatch latch2 = new CountDownLatch(1);
57
58 sb.childOption(ChannelOption.SO_LINGER, 0);
59 sb.childHandler(new ChannelInitializer<>() {
60 @Override
61 protected void initChannel(Channel ch) throws Exception {
62 serverChannelRef.compareAndSet(null, ch);
63 latch.countDown();
64 }
65 });
66 cb.handler(new ChannelInitializer<>() {
67 @Override
68 protected void initChannel(Channel ch) throws Exception {
69 ch.pipeline().addLast(new ChannelHandler() {
70 @Override
71 public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
72 throwableRef.compareAndSet(null, cause);
73 }
74
75 @Override
76 public void channelInactive(ChannelHandlerContext ctx) {
77 latch2.countDown();
78 }
79 });
80 }
81 });
82 Channel sc = sb.bind().asStage().get();
83 Channel cc = cb.connect(sc.localAddress()).asStage().get();
84
85
86 latch.await();
87
88
89 serverChannelRef.get().close();
90
91
92 latch2.await();
93
94
95 Throwable cause = throwableRef.get();
96 assertTrue(cause instanceof IOException,
97 "actual [type, message]: [" + cause.getClass() + ", " + cause.getMessage() + ']');
98
99 assertRstOnCloseException((IOException) cause, cc);
100 }
101
102 @Test
103 @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
104 public void testNoRstIfSoLingerOnClose(TestInfo testInfo) throws Throwable {
105 run(testInfo, this::testNoRstIfSoLingerOnClose);
106 }
107
108 public void testNoRstIfSoLingerOnClose(ServerBootstrap sb, Bootstrap cb) throws Throwable {
109 final AtomicReference<Channel> serverChannelRef = new AtomicReference<>();
110 final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
111 final CountDownLatch latch = new CountDownLatch(1);
112 final CountDownLatch latch2 = new CountDownLatch(1);
113 sb.childHandler(new ChannelInitializer<>() {
114 @Override
115 protected void initChannel(Channel ch) throws Exception {
116 serverChannelRef.compareAndSet(null, ch);
117 latch.countDown();
118 }
119 });
120 cb.handler(new ChannelInitializer<>() {
121 @Override
122 protected void initChannel(Channel ch) throws Exception {
123 ch.pipeline().addLast(new ChannelHandler() {
124 @Override
125 public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
126 throwableRef.compareAndSet(null, cause);
127 }
128
129 @Override
130 public void channelInactive(ChannelHandlerContext ctx) {
131 latch2.countDown();
132 }
133 });
134 }
135 });
136 Channel sc = sb.bind().asStage().get();
137 cb.connect(sc.localAddress()).asStage().sync();
138
139
140 latch.await();
141
142
143 serverChannelRef.get().close();
144
145
146 latch2.await();
147
148
149 assertNull(throwableRef.get());
150 }
151 }