netty5/transport/src/test/java/io/netty/channel/AbstractChannelTest.java
Norman Maurer 0f34345347
Merge ChannelInboundHandler and ChannelOutboundHandler into ChannelHa… (#8957)
Motivation:

In 42742e233f we already added default methods to Channel*Handler and deprecated the Adapter classes to simplify the class hierarchy. With this change we go even further and merge everything into just ChannelHandler. This simplifies things even more in terms of class-hierarchy.

Modifications:

- Merge ChannelInboundHandler | ChannelOutboundHandler into ChannelHandler
- Adjust code to just use ChannelHandler
- Deprecate old interfaces.

Result:

Cleaner and simpler code in terms of class-hierarchy.
2019-03-28 09:28:27 +00:00

229 lines
7.5 KiB
Java

/*
* Copyright 2014 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;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import io.netty.util.NetUtil;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class AbstractChannelTest {
@Test
public void ensureInitialRegistrationFiresActive() throws Throwable {
EventLoop eventLoop = mock(EventLoop.class);
// This allows us to have a single-threaded test
when(eventLoop.inEventLoop()).thenReturn(true);
when(eventLoop.unsafe()).thenReturn(mock(EventLoop.Unsafe.class));
TestChannel channel = new TestChannel(eventLoop);
ChannelHandler handler = mock(ChannelHandler.class);
channel.pipeline().addLast(handler);
registerChannel(channel);
verify(handler).handlerAdded(any(ChannelHandlerContext.class));
verify(handler).channelRegistered(any(ChannelHandlerContext.class));
verify(handler).channelActive(any(ChannelHandlerContext.class));
}
@Test
public void ensureSubsequentRegistrationDoesNotFireActive() throws Throwable {
final EventLoop eventLoop = mock(EventLoop.class);
// This allows us to have a single-threaded test
when(eventLoop.inEventLoop()).thenReturn(true);
when(eventLoop.unsafe()).thenReturn(mock(EventLoop.Unsafe.class));
doAnswer(invocationOnMock -> {
((Runnable) invocationOnMock.getArgument(0)).run();
return null;
}).when(eventLoop).execute(any(Runnable.class));
final TestChannel channel = new TestChannel(eventLoop);
ChannelHandler handler = mock(ChannelHandler.class);
channel.pipeline().addLast(handler);
registerChannel(channel);
channel.unsafe().deregister(new DefaultChannelPromise(channel));
registerChannel(channel);
verify(handler).handlerAdded(any(ChannelHandlerContext.class));
// Should register twice
verify(handler, times(2)) .channelRegistered(any(ChannelHandlerContext.class));
verify(handler).channelActive(any(ChannelHandlerContext.class));
verify(handler).channelUnregistered(any(ChannelHandlerContext.class));
}
@Test
public void ensureDefaultChannelId() {
final EventLoop eventLoop = mock(EventLoop.class);
TestChannel channel = new TestChannel(eventLoop);
final ChannelId channelId = channel.id();
assertTrue(channelId instanceof DefaultChannelId);
}
@Test
public void testClosedChannelExceptionCarryIOException() throws Exception {
final IOException ioException = new IOException();
final EventLoop eventLoop = mock(EventLoop.class);
// This allows us to have a single-threaded test
when(eventLoop.inEventLoop()).thenReturn(true);
when(eventLoop.unsafe()).thenReturn(mock(EventLoop.Unsafe.class));
doAnswer(invocationOnMock -> {
((Runnable) invocationOnMock.getArgument(0)).run();
return null;
}).when(eventLoop).execute(any(Runnable.class));
final Channel channel = new TestChannel(eventLoop) {
private boolean open = true;
private boolean active;
@Override
protected AbstractUnsafe newUnsafe() {
return new AbstractUnsafe() {
@Override
public void connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
active = true;
promise.setSuccess();
}
};
}
@Override
protected void doClose() {
active = false;
open = false;
}
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {
throw ioException;
}
@Override
public boolean isOpen() {
return open;
}
@Override
public boolean isActive() {
return active;
}
};
try {
registerChannel(channel);
channel.connect(new InetSocketAddress(NetUtil.LOCALHOST, 8888)).sync();
assertSame(ioException, channel.writeAndFlush("").await().cause());
assertClosedChannelException(channel.writeAndFlush(""), ioException);
assertClosedChannelException(channel.write(""), ioException);
assertClosedChannelException(channel.bind(new InetSocketAddress(NetUtil.LOCALHOST, 8888)), ioException);
} finally {
channel.close();
}
}
private static void assertClosedChannelException(ChannelFuture future, IOException expected)
throws InterruptedException {
Throwable cause = future.await().cause();
assertTrue(cause instanceof ClosedChannelException);
assertSame(expected, cause.getCause());
}
private static void registerChannel(Channel channel) throws Exception {
DefaultChannelPromise future = new DefaultChannelPromise(channel);
channel.register(future);
future.sync(); // Cause any exceptions to be thrown
}
private static class TestChannel extends AbstractChannel {
private static final ChannelMetadata TEST_METADATA = new ChannelMetadata(false);
private final ChannelConfig config = new DefaultChannelConfig(this);
TestChannel(EventLoop eventLoop) {
super(null, eventLoop);
}
@Override
public ChannelConfig config() {
return config;
}
@Override
public boolean isOpen() {
return true;
}
@Override
public boolean isActive() {
return true;
}
@Override
public ChannelMetadata metadata() {
return TEST_METADATA;
}
@Override
protected AbstractUnsafe newUnsafe() {
return new AbstractUnsafe() {
@Override
public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
promise.setFailure(new UnsupportedOperationException());
}
};
}
@Override
protected SocketAddress localAddress0() {
return null;
}
@Override
protected SocketAddress remoteAddress0() {
return null;
}
@Override
protected void doBind(SocketAddress localAddress) { }
@Override
protected void doDisconnect() { }
@Override
protected void doClose() { }
@Override
protected void doBeginRead() { }
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception { }
}
}