Repository: netty/netty
File: transport-native-epoll/src/test/java/io/netty/channel/epoll/ManualEventLoopTest.java (Java)

Code before:

    @Test
    void testTightSubmissionsEpoll() throws ExecutionException, InterruptedException {
        ManualMultithreadedIoEventLoopGroup group = new ManualMultithreadedIoEventLoopGroup(
                EpollIoHandler.newFactory());
        for (int i = 0; i < 1000; i++) {
            group.submit(() -> {
            }).get();
        }
        group.shutdownGracefully(0, 0, TimeUnit.SECONDS).get();
    }

    @Test
    void testTightSubmissionsNIO() throws ExecutionException, InterruptedException {
        ManualMultithreadedIoEventLoopGroup group = new ManualMultithreadedIoEventLoopGroup(
                NioIoHandler.newFactory());
        for (int i = 0; i < 1000; i++) {
            group.submit(() -> {
            }).get();
        }
        group.shutdownGracefully(0, 0, TimeUnit.SECONDS).get();
    }

    public static class ManualMultithreadedIoEventLoopGroup extends MultiThreadIoEventLoopGroup {

        private ManualIoEventLoopRunner ioEventLoopRunner;
        private Consumer<ManualIoEventLoopRunner> beforeCanBlock;

        public ManualMultithreadedIoEventLoopGroup(IoHandlerFactory ioHandlerFactory) {
            super(1, ioHandlerFactory);
        }

        @Override
        protected IoEventLoop newChild(Executor executor, IoHandlerFactory ioHandlerFactory, Object... args) {
            this.ioEventLoopRunner = new ManualIoEventLoopRunner(this, ioHandlerFactory,
                    executor, this::beforeCanBlock);
            return ioEventLoopRunner.ioEventLoop;
        }

        protected void beforeCanBlock(Executor executor) {
        }

        private static class ManualIoEventLoopRunner implements Executor {

            private final ManualIoEventLoop ioEventLoop;
            private final Queue<Runnable> otherTasks = new ConcurrentLinkedQueue<>();

            ManualIoEventLoopRunner(IoEventLoopGroup parent, IoHandlerFactory factory,
                                    Executor executor, Consumer<Executor> beforeCanBlock) {
                this.ioEventLoop = new ManualIoEventLoop(parent, null, factory) {
                    @Override

Review comment (suggestion):
@yawkat I can move the test specific of the `canBlock` new API on the manual event loop tests - without any existing io handler too. 

Code after:
        private Consumer<ManualIoEventLoopRunner> beforeCanBlock;

        public ManualMultithreadedIoEventLoopGroup(IoHandlerFactory ioHandlerFactory) {
            super(1, ioHandlerFactory);
        }

        @Override
        protected IoEventLoop newChild(Executor executor, IoHandlerFactory ioHandlerFactory, Object... args) {
            this.ioEventLoopRunner = new ManualIoEventLoopRunner(this, ioHandlerFactory,
                    executor, this::beforeCanBlock);
            return ioEventLoopRunner.ioEventLoop;
        }

        protected void beforeCanBlock(Executor executor) {
        }

        private static class ManualIoEventLoopRunner implements Executor {

            private final ManualIoEventLoop ioEventLoop;
            private final Queue<Runnable> otherTasks = new ConcurrentLinkedQueue<>();

            ManualIoEventLoopRunner(IoEventLoopGroup parent, IoHandlerFactory factory,
                                    Executor executor, Consumer<Executor> beforeCanBlock) {
                this.ioEventLoop = new ManualIoEventLoop(parent, null, factory) {
                    @Override
                    protected boolean canBlock() {
                        if (beforeCanBlock != null) {
                            beforeCanBlock.accept(ManualIoEventLoopRunner.this);
                        }
                        return otherTasks.isEmpty();
                    }
                };
                CountDownLatch started = new CountDownLatch(1);
                executor.execute(() -> {
                    ioEventLoop.setOwningThread(Thread.currentThread());
                    // it would force a first init
                    ioEventLoop.runNow();
                    started.countDown();
                    mainLoop();
                });
                try {
                    started.await();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException(e);
                }
            }

            private void mainLoop() {
                while (!ioEventLoop.isShuttingDown()) {
                    ioEventLoop.run(0);