/*
 * Copyright 2017 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.channel.DefaultSelectStrategyFactory;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.testsuite.transport.AbstractSingleThreadEventLoopTest;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.RejectedExecutionHandlers;
import io.netty.util.concurrent.ThreadPerTaskExecutor;
import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class EpollEventLoopTest extends AbstractSingleThreadEventLoopTest {

    @Override
    protected EventLoopGroup newEventLoopGroup() {
        return new EpollEventLoopGroup();
    }

    @Override
    protected ServerSocketChannel newChannel() {
        return new EpollServerSocketChannel();
    }

    @Test
    public void testScheduleBigDelayNotOverflow() {
        final AtomicReference<Throwable> capture = new AtomicReference<Throwable>();

        final EventLoopGroup group = new EpollEventLoop(null,
                new ThreadPerTaskExecutor(new DefaultThreadFactory(getClass())), 0,
                DefaultSelectStrategyFactory.INSTANCE.newSelectStrategy(), RejectedExecutionHandlers.reject(), null) {
            @Override
            void handleLoopException(Throwable t) {
                capture.set(t);
                super.handleLoopException(t);
            }
        };

        try {
            final EventLoop eventLoop = group.next();
            Future<?> future = eventLoop.schedule(new Runnable() {
                @Override
                public void run() {
                    // NOOP
                }
            }, Long.MAX_VALUE, TimeUnit.MILLISECONDS);

            assertFalse(future.awaitUninterruptibly(1000));
            assertTrue(future.cancel(true));
            assertNull(capture.get());
        } finally {
            group.shutdownGracefully();
        }
    }
}

@@ -842,16 +842,61 @@
 hannel;%0A
+import io.netty.channel.unix.FileDescriptor;%0A
 import i
@@ -958,16 +958,16 @@
 opTest;%0A
-
 import i
@@ -1190,16 +1190,44 @@
 .Test;%0A%0A
+import java.io.IOException;%0A
 import j
@@ -1256,16 +1256,66 @@
 meUnit;%0A
+import java.util.concurrent.atomic.AtomicInteger;%0A
 import j
@@ -1359,16 +1359,61 @@
 rence;%0A%0A
+import static org.junit.Assert.assertEquals;%0A
 import s
@@ -2893,24 +2893,24 @@
 %7D finally %7B%0A
-
             
@@ -2952,11 +2952,1996 @@
  %7D%0A    %7D
+%0A%0A    @Test%0A    public void testEventFDETSemantics() throws Throwable %7B%0A        final FileDescriptor epoll = Native.newEpollCreate();%0A        final FileDescriptor eventFd = Native.newEventFd();%0A        final FileDescriptor timerFd = Native.newTimerFd();%0A        final EpollEventArray array = new EpollEventArray(1024);%0A        try %7B%0A            Native.epollCtlAdd(epoll.intValue(), eventFd.intValue(), Native.EPOLLIN %7C Native.EPOLLET);%0A            final AtomicReference%3CThrowable%3E causeRef = new AtomicReference%3CThrowable%3E();%0A            final AtomicInteger integer = new AtomicInteger();%0A            final Thread t = new Thread(new Runnable() %7B%0A                @Override%0A                public void run() %7B%0A                    try %7B%0A                        for (int i = 0; i %3C 2; i++) %7B%0A                            int ready = Native.epollWait(epoll, array, timerFd, -1, -1);%0A                            assertEquals(1, ready);%0A                            assertEquals(eventFd.intValue(), array.fd(0));%0A                            integer.incrementAndGet();%0A                        %7D%0A                    %7D catch (IOException e) %7B%0A                        causeRef.set(e);%0A                    %7D%0A                %7D%0A            %7D);%0A            t.start();%0A            Native.eventFdWrite(eventFd.intValue(), 1);%0A%0A            // Spin until we was the wakeup.%0A            while (integer.get() != 1) %7B%0A                Thread.sleep(10);%0A            %7D%0A            // Sleep for a short moment to ensure there is not other wakeup.%0A            Thread.sleep(1000);%0A            assertEquals(1, integer.get());%0A            Native.eventFdWrite(eventFd.intValue(), 1);%0A            t.join();%0A            Throwable cause = causeRef.get();%0A            if (cause != null) %7B%0A                throw cause;%0A            %7D%0A            assertEquals(2, integer.get());%0A        %7D finally %7B%0A            array.free();%0A            epoll.close();%0A            eventFd.close();%0A            timerFd.close();%0A        %7D%0A    %7D
 %0A%7D%0A

Add testcase to prove that ET semantics for eventFD are correct (#9385)