I have a Netty TCP Server with Spring Boot 2.3.1
.
I have been looking for many resources for testing handlers for Netty, like
However, it didn't work for me.
For EmbeddedChannel I have following error - Your remote address is embedded.
Here is code:
@ActiveProfiles("test")
@RunWith(MockitoJUnitRunner.class)
public class ProcessingHandlerTest_Embedded {
@Mock
private PermissionService permissionService;
private EmbeddedChannel embeddedChannel;
private final Gson gson = new Gson();
private ProcessingHandler processingHandler;
@Before
public void setUp() {
processingHandler = new ProcessingHandler(permissionService);
embeddedChannel = new EmbeddedChannel(processingHandler);
}
@Test
public void testHeartbeatMessage() {
// given
HeartbeatRequest heartbeatMessage = HeartbeatRequest.builder()
.messageID("heartbeat")
.build();
HeartbeatResponse response = HeartbeatResponse.builder()
.responseCode("ok")
.build();
String request = gson.toJson(heartbeatMessage).concat("\r\n");
String expected = gson.toJson(response).concat("\r\n");
// when
embeddedChannel.writeInbound(request);
// then
Queue<Object> outboundMessages = embeddedChannel.outboundMessages();
assertEquals(expected, outboundMessages.poll());
}
}
Output:
22:21:29.062 [main] INFO handler.ProcessingHandler - CLIENT_IP: embedded
22:21:29.062 [main] INFO handler.ProcessingHandler - CLIENT_REQUEST: {"messageID":"heartbeat"}
22:21:29.067 [main] DEBUG handler.ProcessingHandler - heartbeat request: HeartbeatRequest(messageID=heartbeat)
org.junit.ComparisonFailure:
<Click to see difference>
I tried something with a remote address:
@ActiveProfiles("test")
@RunWith(MockitoJUnitRunner.class)
public class ProcessingHandlerTest {
@Mock
private PermissionService permissionService;
private final Gson gson = new Gson();
private ProcessingHandler processingHandler;
@Mock
private ChannelHandlerContext channelHandlerContext;
@Mock
private Channel channel;
@Mock
private SocketAddress remoteAddress;
@Before
public void setUp() {
processingHandler = new ProcessingHandler(permissionService);
when(channelHandlerContext.channel()).thenReturn(channel);
when(channelHandlerContext.channel().remoteAddress()).thenReturn(remoteAddress);
}
@Test
public void testHeartbeatMessage() {
// given
HeartbeatRequest heartbeatMessage = HeartbeatRequest.builder()
.messageID("heartbeat")
.build();
HeartbeatResponse response = HeartbeatResponse.builder()
.responseCode("ok")
.build();
String request = gson.toJson(heartbeatMessage).concat("\r\n");
String expected = gson.toJson(response).concat("\r\n");
// when
processingHandler.channelRead(channelHandlerContext, request);
// then
}
}
Output:
22:26:06.119 [main] INFO handler.ProcessingHandler - CLIENT_IP: null
22:26:06.124 [main] INFO handler.ProcessingHandler - CLIENT_REQUEST: {"messageID":"heartbeat"}
22:26:06.127 [main] DEBUG handler.ProcessingHandler - heartbeat request: HeartbeatRequest(messageID=heartbeat)
However, I don't know how to do exact testing for such a case.
Here is a snippet from configuration:
@Bean
@SneakyThrows
public InetSocketAddress tcpSocketAddress() {
// for now, hostname is: localhost/127.0.0.1:9090
return new InetSocketAddress("localhost", nettyProperties.getTcpPort());
// for real client devices: A05264/172.28.1.162:9090
// return new InetSocketAddress(InetAddress.getLocalHost(), nettyProperties.getTcpPort());
}
@Component
@RequiredArgsConstructor
public class QrReaderChannelInitializer extends ChannelInitializer<SocketChannel> {
private final StringEncoder stringEncoder = new StringEncoder();
private final StringDecoder stringDecoder = new StringDecoder();
private final QrReaderProcessingHandler readerServerHandler;
private final NettyProperties nettyProperties;
@Override
protected void initChannel(SocketChannel socketChannel) {
ChannelPipeline pipeline = socketChannel.pipeline();
// Add the text line codec combination first
pipeline.addLast(new DelimiterBasedFrameDecoder(1024 * 1024, Delimiters.lineDelimiter()));
pipeline.addLast(new ReadTimeoutHandler(nettyProperties.getClientTimeout()));
pipeline.addLast(stringDecoder);
pipeline.addLast(stringEncoder);
pipeline.addLast(readerServerHandler);
}
}
The handler is a typical implementation of ChannelInboundHandlerAdapter
with overriding main methods.
How to test Handler with Spring Boot?