Repository: netty/netty
File: codec-native-quic/src/test/java/io/netty/handler/codec/quic/QuicStreamShutdownTest.java (Java)

Code before:

                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            QuicStreamChannel streamChannel = (QuicStreamChannel) ctx.channel();
                            ByteBuf buffer = (ByteBuf) msg;
                            buffer.release();
                            streamChannel.shutdownOutput(100).addListener(new ChannelFutureListener() {
                                @Override
                                public void operationComplete(ChannelFuture f) throws Exception {
                                    if (!f.isSuccess()) {
                                        errorRef.compareAndSet(null, f.cause());
                                    }
                                    latch.countDown();
                                }
                            });
                        }
                    });

            channel = QuicTestUtils.newClient(executor);
            QuicChannel quicChannel = QuicTestUtils.newQuicChannelBootstrap(channel)
                    .handler(new ChannelInboundHandlerAdapter())
                    .streamHandler(new ChannelInboundHandlerAdapter())
                    .remoteAddress(server.localAddress())
                    .connect()
                    .get();

            QuicStreamChannel streamChannel = quicChannel.createStream(QuicStreamType.BIDIRECTIONAL,
                    new ChannelInboundHandlerAdapter() {
                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                            if (cause instanceof QuicStreamResetException) {
                                QuicStreamResetException reset = (QuicStreamResetException) cause;
                                applicationErrorCode.set(reset.applicationProtocolCode());
                                latch.countDown();
                            } else {
                                errorRef.set(cause);
                            }
                        }
                    }).sync().getNow();

            streamChannel.writeAndFlush(Unpooled.buffer().writeInt(4)).sync();

            if (!latch.await(5, TimeUnit.SECONDS)) {
                fail("Timeout while waiting for completion", errorRef.get());
            }
            Throwable error = errorRef.get();
            if (error != null) {
                fail("Failure during execution", error);
            }
            assertEquals(100, applicationErrorCode.get());
        } finally {

Review comment (suggestion):
I think we need to countdown the latch in both cases. 
```suggestion
                            if (cause instanceof QuicStreamResetException) {
                                QuicStreamResetException reset = (QuicStreamResetException) cause;
                                applicationErrorCode.set(reset.applicationProtocolCode());
                            } else {
                                errorRef.set(cause);
                            }
                            latch.countDown();
```

Code after:
                                        errorRef.compareAndSet(null, f.cause());
                                    }
                                    latch.countDown();
                                }
                            });
                        }
                    });

            channel = QuicTestUtils.newClient(executor);
            QuicChannel quicChannel = QuicTestUtils.newQuicChannelBootstrap(channel)
                    .handler(new ChannelInboundHandlerAdapter())
                    .streamHandler(new ChannelInboundHandlerAdapter())
                    .remoteAddress(server.localAddress())
                    .connect()
                    .get();

            QuicStreamChannel streamChannel = quicChannel.createStream(QuicStreamType.BIDIRECTIONAL,
                    new ChannelInboundHandlerAdapter() {
                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                            if (cause instanceof QuicStreamResetException) {
                                QuicStreamResetException reset = (QuicStreamResetException) cause;
                                applicationErrorCode.set(reset.applicationProtocolCode());
                            } else {
                                errorRef.set(cause);
                            }
                            latch.countDown();
                        }
                    }).sync().getNow();

            streamChannel.writeAndFlush(Unpooled.buffer().writeInt(4)).sync();

            if (!latch.await(5, TimeUnit.SECONDS)) {
                fail("Timeout while waiting for completion", errorRef.get());
            }
            Throwable error = errorRef.get();
            if (error != null) {
                fail("Failure during execution", error);
            }
            assertEquals(100, applicationErrorCode.get());
        } finally {
            QuicTestUtils.closeIfNotNull(channel);
            QuicTestUtils.closeIfNotNull(server);

            shutdown(executor);
        }
    }
}