From 12f6500a4fdf39f88cc1d5bd4649926a22c7e170 Mon Sep 17 00:00:00 2001 From: Scott Mitchell Date: Fri, 15 Jun 2018 01:28:50 -0700 Subject: [PATCH] Epoll and Kqueue shouldn't read by default (#8024) Motivation: Epoll and Kqueue channels have internal state which forces a single read operation after channel construction. This violates the Channel#read() interface which indicates that data shouldn't be delivered until this method is called. The behavior is also inconsistent with the NIO transport. Modifications: - Epoll and Kqueue shouldn't unconditionally read upon initialization, and instead should rely upon Channel#read() or auto_read. Result: Epoll and Kqueue are more consistent with NIO. --- .../SocketDataReadInitialStateTest.java | 184 ++++++++++++++++++ .../channel/epoll/AbstractEpollChannel.java | 19 +- .../epoll/AbstractEpollServerChannel.java | 2 +- .../epoll/AbstractEpollStreamChannel.java | 6 +- .../channel/epoll/EpollDatagramChannel.java | 4 +- ...lDomainSocketDataReadInitialStateTest.java | 36 ++++ ...EpollETSocketDataReadInitialStateTest.java | 39 ++++ ...EpollLTSocketDataReadInitialStateTest.java | 39 ++++ .../channel/kqueue/AbstractKQueueChannel.java | 5 +- ...eDomainSocketDataReadInitialStateTest.java | 36 ++++ ...QueueETSocketDataReadInitialStateTest.java | 30 +++ 11 files changed, 378 insertions(+), 22 deletions(-) create mode 100644 testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketDataReadInitialStateTest.java create mode 100644 transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDomainSocketDataReadInitialStateTest.java create mode 100644 transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollETSocketDataReadInitialStateTest.java create mode 100644 transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollLTSocketDataReadInitialStateTest.java create mode 100644 transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueDomainSocketDataReadInitialStateTest.java create mode 100644 transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueETSocketDataReadInitialStateTest.java diff --git a/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketDataReadInitialStateTest.java b/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..f4d218d957 --- /dev/null +++ b/testsuite/src/main/java/io/netty/testsuite/transport/socket/SocketDataReadInitialStateTest.java @@ -0,0 +1,184 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.testsuite.transport.socket; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.SimpleChannelInboundHandler; +import org.junit.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import static io.netty.channel.ChannelOption.AUTO_READ; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class SocketDataReadInitialStateTest extends AbstractSocketTest { + @Test(timeout = 10000) + public void testAutoReadOffNoDataReadUntilReadCalled() throws Throwable { + run(); + } + + public void testAutoReadOffNoDataReadUntilReadCalled(ServerBootstrap sb, Bootstrap cb) throws Throwable { + Channel serverChannel = null; + Channel clientChannel = null; + final int sleepMs = 100; + try { + sb.option(AUTO_READ, false); + sb.childOption(AUTO_READ, false); + cb.option(AUTO_READ, false); + final CountDownLatch serverReadyLatch = new CountDownLatch(1); + final CountDownLatch acceptorReadLatch = new CountDownLatch(1); + final CountDownLatch serverReadLatch = new CountDownLatch(1); + final CountDownLatch clientReadLatch = new CountDownLatch(1); + final AtomicReference serverConnectedChannelRef = new AtomicReference(); + + sb.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + acceptorReadLatch.countDown(); + ctx.fireChannelRead(msg); + } + }); + } + }); + + sb.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + serverConnectedChannelRef.set(ch); + ch.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { + ctx.writeAndFlush(msg.retainedDuplicate()); + serverReadLatch.countDown(); + } + }); + serverReadyLatch.countDown(); + } + }); + + cb.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) { + clientReadLatch.countDown(); + } + }); + } + }); + + serverChannel = sb.bind().sync().channel(); + clientChannel = cb.connect(serverChannel.localAddress()).sync().channel(); + clientChannel.writeAndFlush(clientChannel.alloc().buffer().writeZero(1)).syncUninterruptibly(); + + // The acceptor shouldn't read any data until we call read() below, but give it some time to see if it will. + Thread.sleep(sleepMs); + assertEquals(1, acceptorReadLatch.getCount()); + serverChannel.read(); + serverReadyLatch.await(); + + Channel serverConnectedChannel = serverConnectedChannelRef.get(); + assertNotNull(serverConnectedChannel); + + // Allow some amount of time for the server peer to receive the message (which isn't expected to happen + // until we call read() below). + Thread.sleep(sleepMs); + assertEquals(1, serverReadLatch.getCount()); + serverConnectedChannel.read(); + serverReadLatch.await(); + + // Allow some amount of time for the client to read the echo. + Thread.sleep(sleepMs); + assertEquals(1, clientReadLatch.getCount()); + clientChannel.read(); + clientReadLatch.await(); + } finally { + if (serverChannel != null) { + serverChannel.close().sync(); + } + if (clientChannel != null) { + clientChannel.close().sync(); + } + } + } + + @Test(timeout = 10000) + public void testAutoReadOnDataReadImmediately() throws Throwable { + run(); + } + + public void testAutoReadOnDataReadImmediately(ServerBootstrap sb, Bootstrap cb) throws Throwable { + Channel serverChannel = null; + Channel clientChannel = null; + try { + sb.option(AUTO_READ, true); + sb.childOption(AUTO_READ, true); + cb.option(AUTO_READ, true); + final CountDownLatch serverReadLatch = new CountDownLatch(1); + final CountDownLatch clientReadLatch = new CountDownLatch(1); + + sb.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { + ctx.writeAndFlush(msg.retainedDuplicate()); + serverReadLatch.countDown(); + } + }); + } + }); + + cb.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) { + clientReadLatch.countDown(); + } + }); + } + }); + + serverChannel = sb.bind().sync().channel(); + clientChannel = cb.connect(serverChannel.localAddress()).sync().channel(); + clientChannel.writeAndFlush(clientChannel.alloc().buffer().writeZero(1)).syncUninterruptibly(); + serverReadLatch.await(); + clientReadLatch.await(); + } finally { + if (serverChannel != null) { + serverChannel.close().sync(); + } + if (clientChannel != null) { + clientChannel.close().sync(); + } + } + } +} diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java index 03574b9715..25ae95b2d4 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java @@ -60,7 +60,6 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann private static final ClosedChannelException DO_CLOSE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractEpollChannel.class, "doClose()"); private static final ChannelMetadata METADATA = new ChannelMetadata(false); - private final int readFlag; final LinuxSocket socket; /** * The future of the current connection attempt. If not null, subsequent @@ -79,15 +78,13 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann protected volatile boolean active; - AbstractEpollChannel(LinuxSocket fd, int flag) { - this(null, fd, flag, false); + AbstractEpollChannel(LinuxSocket fd) { + this(null, fd, false); } - AbstractEpollChannel(Channel parent, LinuxSocket fd, int flag, boolean active) { + AbstractEpollChannel(Channel parent, LinuxSocket fd, boolean active) { super(parent); socket = checkNotNull(fd, "fd"); - readFlag = flag; - flags |= flag; this.active = active; if (active) { // Directly cache the remote and local addresses @@ -97,11 +94,9 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann } } - AbstractEpollChannel(Channel parent, LinuxSocket fd, int flag, SocketAddress remote) { + AbstractEpollChannel(Channel parent, LinuxSocket fd, SocketAddress remote) { super(parent); socket = checkNotNull(fd, "fd"); - readFlag = flag; - flags |= flag; active = true; // Directly cache the remote and local addresses // See https://github.com/netty/netty/issues/2359 @@ -228,7 +223,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann // We must set the read flag here as it is possible the user didn't read in the last read loop, the // executeEpollInReadyRunnable could read nothing, and if the user doesn't explicitly call read they will // never get data after this. - setFlag(readFlag); + setFlag(Native.EPOLLIN); // If EPOLL ET mode is enabled and auto read was toggled off on the last read loop then we may not be notified // again if we didn't consume all the data. So we force a read operation here if there maybe more data. @@ -268,7 +263,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann } else { // The EventLoop is not registered atm so just update the flags so the correct value // will be used once the channel is registered - flags &= ~readFlag; + flags &= ~Native.EPOLLIN; } } @@ -535,7 +530,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann assert eventLoop().inEventLoop(); try { readPending = false; - clearFlag(readFlag); + clearFlag(Native.EPOLLIN); } catch (IOException e) { // When this happens there is something completely wrong with either the filedescriptor or epoll, // so fire the exception through the pipeline and close the Channel. diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollServerChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollServerChannel.java index ebda9ebfe7..b7ccf37b2e 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollServerChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollServerChannel.java @@ -39,7 +39,7 @@ public abstract class AbstractEpollServerChannel extends AbstractEpollChannel im } AbstractEpollServerChannel(LinuxSocket fd, boolean active) { - super(null, fd, Native.EPOLLIN, active); + super(null, fd, active); } @Override diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java index 7bb9e595bf..ea871db3e1 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java @@ -99,19 +99,19 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel im } AbstractEpollStreamChannel(Channel parent, LinuxSocket fd) { - super(parent, fd, Native.EPOLLIN, true); + super(parent, fd, true); // Add EPOLLRDHUP so we are notified once the remote peer close the connection. flags |= Native.EPOLLRDHUP; } AbstractEpollStreamChannel(Channel parent, LinuxSocket fd, SocketAddress remote) { - super(parent, fd, Native.EPOLLIN, remote); + super(parent, fd, remote); // Add EPOLLRDHUP so we are notified once the remote peer close the connection. flags |= Native.EPOLLRDHUP; } protected AbstractEpollStreamChannel(LinuxSocket fd, boolean active) { - super(null, fd, Native.EPOLLIN, active); + super(null, fd, active); // Add EPOLLRDHUP so we are notified once the remote peer close the connection. flags |= Native.EPOLLRDHUP; } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java index a19191d596..d9f48464f5 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java @@ -59,7 +59,7 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements private volatile boolean connected; public EpollDatagramChannel() { - super(newSocketDgram(), Native.EPOLLIN); + super(newSocketDgram()); config = new EpollDatagramChannelConfig(this); } @@ -68,7 +68,7 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements } EpollDatagramChannel(LinuxSocket fd) { - super(null, fd, Native.EPOLLIN, true); + super(null, fd, true); config = new EpollDatagramChannelConfig(this); } diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDomainSocketDataReadInitialStateTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDomainSocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..9f848cd18d --- /dev/null +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDomainSocketDataReadInitialStateTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.epoll; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest; + +import java.net.SocketAddress; +import java.util.List; + +public class EpollDomainSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest { + @Override + protected SocketAddress newSocketAddress() { + return EpollSocketTestPermutation.newSocketAddress(); + } + + @Override + protected List> newFactories() { + return EpollSocketTestPermutation.INSTANCE.domainSocket(); + } +} diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollETSocketDataReadInitialStateTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollETSocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..9c27f25030 --- /dev/null +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollETSocketDataReadInitialStateTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.epoll; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBufAllocator; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest; + +import java.util.List; + +public class EpollETSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest { + @Override + protected List> newFactories() { + return EpollSocketTestPermutation.INSTANCE.socket(); + } + + @Override + protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) { + super.configure(bootstrap, bootstrap2, allocator); + bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED) + .childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED); + bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED); + } +} diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollLTSocketDataReadInitialStateTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollLTSocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..78614edd35 --- /dev/null +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollLTSocketDataReadInitialStateTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.epoll; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBufAllocator; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest; + +import java.util.List; + +public class EpollLTSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest { + @Override + protected List> newFactories() { + return EpollSocketTestPermutation.INSTANCE.socket(); + } + + @Override + protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) { + super.configure(bootstrap, bootstrap2, allocator); + bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) + .childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED); + bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED); + } +} diff --git a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java index 7ca2bd9f1c..6073fa9ca1 100644 --- a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java +++ b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java @@ -65,7 +65,7 @@ abstract class AbstractKQueueChannel extends AbstractChannel implements UnixChan private SocketAddress requestedRemoteAddress; final BsdSocket socket; - private boolean readFilterEnabled = true; + private boolean readFilterEnabled; private boolean writeFilterEnabled; boolean readReadyRunnablePending; boolean inputClosedSeenErrorOnRead; @@ -187,9 +187,6 @@ abstract class AbstractKQueueChannel extends AbstractChannel implements UnixChan evSet0(Native.EVFILT_SOCK, Native.EV_DELETE, 0); ((KQueueEventLoop) eventLoop()).remove(this); - - // Set the filters back to the initial state in case this channel is registered with another event loop. - readFilterEnabled = true; } @Override diff --git a/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueDomainSocketDataReadInitialStateTest.java b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueDomainSocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..10e538b8e4 --- /dev/null +++ b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueDomainSocketDataReadInitialStateTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.kqueue; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest; + +import java.net.SocketAddress; +import java.util.List; + +public class KQueueDomainSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest { + @Override + protected SocketAddress newSocketAddress() { + return KQueueSocketTestPermutation.newSocketAddress(); + } + + @Override + protected List> newFactories() { + return KQueueSocketTestPermutation.INSTANCE.domainSocket(); + } +} diff --git a/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueETSocketDataReadInitialStateTest.java b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueETSocketDataReadInitialStateTest.java new file mode 100644 index 0000000000..3055b1dafe --- /dev/null +++ b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueETSocketDataReadInitialStateTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.kqueue; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.testsuite.transport.TestsuitePermutation; +import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest; + +import java.util.List; + +public class KQueueETSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest { + @Override + protected List> newFactories() { + return KQueueSocketTestPermutation.INSTANCE.socket(); + } +}