@Before
  public void setUp() throws Exception {
    ByteBufPool.clear();
    ByteBufPool.setSizes(0, Integer.MAX_VALUE);

    eventloop = new NioEventloop();
  }
  @Test
  public void testResolve() throws Exception {
    eventloop.postLater(
        new Runnable() {
          @Override
          public void run() {
            try {
              DatagramChannel datagramChannel =
                  createDatagramChannel(defaultDatagramSocketSettings(), null, null);
              dnsClientConnection = new DnsClientConnection(eventloop, datagramChannel);
              dnsClientConnection.register();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        });

    eventloop.postLater(
        new Runnable() {
          @Override
          public void run() {
            dnsClientConnection.resolve4(
                "www.github.com", DNS_SERVER_ADDRESS, TIMEOUT, new DnsResolveCallback());
          }
        });

    eventloop.postLater(
        new Runnable() {
          @Override
          public void run() {
            dnsClientConnection.resolve4(
                "www.kpi.ua", DNS_SERVER_ADDRESS, TIMEOUT, new DnsResolveCallback());
          }
        });

    eventloop.postLater(
        new Runnable() {
          @Override
          public void run() {
            dnsClientConnection.resolve4(
                "www.google.com", DNS_SERVER_ADDRESS, TIMEOUT, new DnsResolveCallback());
          }
        });

    eventloop.run();

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }
  public static void main(String[] args) throws Exception {
    ServerOptions options = ServerOptions.parseCommandLine(args);
    if (options == null) return;
    info(options);

    ThrottlingController throttlingController = ThrottlingController.create();
    final Eventloop eventloop =
        Eventloop.create()
            .withThrottlingController(throttlingController)
            .withFatalErrorHandler(rethrowOnAnyError());

    final HttpThrottlingServer server = new HttpThrottlingServer(eventloop, options);

    MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
    DynamicMBeanFactory mBeanFactory = JmxMBeans.factory();
    mbeanServer.registerMBean(
        mBeanFactory.createFor(asList(eventloop), true),
        new ObjectName(Eventloop.class.getPackage().getName() + ":type=Eventloop"));
    mbeanServer.registerMBean(
        ByteBufPool.getStats(),
        new ObjectName(ByteBufPool.class.getPackage().getName() + ":type=ByteBufPool"));
    mbeanServer.registerMBean(
        mBeanFactory.createFor(asList(throttlingController), true),
        new ObjectName(
            ThrottlingController.class.getPackage().getName() + ":type=ThrottlingController"));
    server.start();

    eventloop.run();
  }
  @Test
  public void simpleWorkers() throws IOException, ExecutionException, InterruptedException {
    final ArrayList<AsyncHttpServer> workerServers = new ArrayList<>();

    for (int i = 0; i < WORKERS; i++) {
      final NioEventloop eventloop = new NioEventloop();
      eventloop.keepAlive(true);
      AsyncHttpServer server = echoServer(eventloop, i);
      workerServers.add(server);
      new Thread(eventloop).start();
    }

    NioEventloop primaryEventloop = new NioEventloop();
    PrimaryNioServer primaryNioServer =
        PrimaryNioServer.create(primaryEventloop)
            .workerNioServers(workerServers)
            .setListenPort(PORT);
    primaryNioServer.listen();

    Thread primaryThread = new Thread(primaryEventloop);
    primaryThread.start();

    Socket socket1 = new Socket();
    Socket socket2 = new Socket();
    socket1.connect(new InetSocketAddress(PORT));
    socket2.connect(new InetSocketAddress(PORT));

    socket1
        .getOutputStream()
        .write(
            encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: keep-alive\n\r\n"));
    readAndAssert(
        socket1.getInputStream(),
        "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: 22\r\n\r\nHello world: worker #0");
    socket1
        .getOutputStream()
        .write(encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: close\n\r\n"));
    readAndAssert(
        socket1.getInputStream(),
        "HTTP/1.1 200 OK\r\nContent-Length: 22\r\n\r\nHello world: worker #0");
    assertTrue(toByteArray(socket1.getInputStream()).length == 0);
    socket1.close();

    socket2
        .getOutputStream()
        .write(
            encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: keep-alive\n\r\n"));
    readAndAssert(
        socket2.getInputStream(),
        "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: 22\r\n\r\nHello world: worker #1");
    socket2
        .getOutputStream()
        .write(encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: close\n\r\n"));
    readAndAssert(
        socket2.getInputStream(),
        "HTTP/1.1 200 OK\r\nContent-Length: 22\r\n\r\nHello world: worker #1");
    assertTrue(toByteArray(socket2.getInputStream()).length == 0);
    socket2.close();

    primaryNioServer.closeFuture().get();
    primaryThread.join();
    for (AsyncHttpServer server : workerServers) {
      server.getNioEventloop().keepAlive(false);
      server.closeFuture().get();
    }

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }
 @Before
 public void before() {
   ByteBufPool.clear();
   ByteBufPool.setSizes(0, Integer.MAX_VALUE);
 }
  @Test
  public void serviceRunner() throws ExecutionException, InterruptedException, IOException {
    ArrayList<NioEventloopRunner> workerServices = new ArrayList<>();
    ArrayList<AsyncHttpServer> workerServers = new ArrayList<>();

    for (int i = 0; i < WORKERS; i++) {
      NioEventloop workerEventloop = new NioEventloop();
      AsyncHttpServer workerServer = echoServer(workerEventloop, i);
      workerServers.add(workerServer);

      workerServices.add(new NioEventloopRunner(workerEventloop).addNioServers(workerServer));
    }

    NioEventloop primaryEventloop = new NioEventloop();
    PrimaryNioServer primaryNioServer =
        PrimaryNioServer.create(primaryEventloop)
            .workerNioServers(workerServers)
            .setListenPort(PORT);

    NioEventloopRunner primaryService =
        new NioEventloopRunner(primaryEventloop)
            .addNioServers(primaryNioServer)
            .addConcurrentServices(workerServices);

    primaryService.startFuture().get();

    Socket socket1 = new Socket();
    Socket socket2 = new Socket();
    socket1.connect(new InetSocketAddress(PORT));
    socket2.connect(new InetSocketAddress(PORT));

    socket1
        .getOutputStream()
        .write(
            encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: keep-alive\n\r\n"));
    readAndAssert(
        socket1.getInputStream(),
        "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: 22\r\n\r\nHello world: worker #0");
    socket1
        .getOutputStream()
        .write(encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: close\n\r\n"));
    readAndAssert(
        socket1.getInputStream(),
        "HTTP/1.1 200 OK\r\nContent-Length: 22\r\n\r\nHello world: worker #0");
    assertTrue(toByteArray(socket1.getInputStream()).length == 0);
    socket1.close();

    socket2
        .getOutputStream()
        .write(
            encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: keep-alive\n\r\n"));
    readAndAssert(
        socket2.getInputStream(),
        "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: 22\r\n\r\nHello world: worker #1");
    socket2
        .getOutputStream()
        .write(encodeAscii("GET /hello HTTP1.1\r\nHost: localhost\r\nConnection: close\n\r\n"));
    readAndAssert(
        socket2.getInputStream(),
        "HTTP/1.1 200 OK\r\nContent-Length: 22\r\n\r\nHello world: worker #1");
    assertTrue(toByteArray(socket2.getInputStream()).length == 0);
    socket2.close();

    primaryService.stopFuture().get();

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }
  @Test
  public void test() throws Exception {
    final List<Integer> source = Lists.newArrayList();
    for (int i = 0; i < 5; i++) {
      source.add(i);
    }

    final NioEventloop eventloop = new NioEventloop();

    final StreamConsumers.ToList<Integer> consumerToList = StreamConsumers.toList(eventloop);

    SimpleNioServer server =
        new SimpleNioServer(eventloop) {
          @Override
          protected SocketConnection createConnection(SocketChannel socketChannel) {
            return new TcpStreamSocketConnection(eventloop, socketChannel) {
              @Override
              protected void wire(
                  StreamProducer<ByteBuf> socketReader, StreamConsumer<ByteBuf> socketWriter) {
                StreamBinaryDeserializer<Integer> streamDeserializer =
                    new StreamBinaryDeserializer<>(eventloop, intSerializer(), 10);
                streamDeserializer.streamTo(consumerToList);
                socketReader.streamTo(streamDeserializer);
              }
            };
          }
        };
    server.setListenAddress(address).acceptOnce();
    server.listen();

    final StreamBinarySerializer<Integer> streamSerializer =
        new StreamBinarySerializer<>(eventloop, intSerializer(), 1, 10, 0, false);
    reconnect(
        eventloop,
        address,
        defaultSocketSettings(),
        3,
        100L,
        new ConnectCallback() {
          @Override
          public void onConnect(SocketChannel socketChannel) {
            SocketConnection connection =
                new TcpStreamSocketConnection(eventloop, socketChannel) {
                  @Override
                  protected void wire(
                      StreamProducer<ByteBuf> socketReader, StreamConsumer<ByteBuf> socketWriter) {
                    streamSerializer.streamTo(socketWriter);
                    StreamProducers.ofIterable(eventloop, source).streamTo(streamSerializer);
                  }
                };
            connection.register();
          }

          @Override
          public void onException(Exception exception) {
            fail();
          }
        });

    eventloop.run();

    assertEquals(source, consumerToList.getList());

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }
  @Test
  public void testPing() throws Exception {
    final NioEventloop eventloop = new NioEventloop();

    SimpleNioServer server =
        new SimpleNioServer(eventloop) {
          @Override
          protected SocketConnection createConnection(SocketChannel socketChannel) {
            return new StreamMessagingConnection<>(
                    eventloop,
                    socketChannel,
                    new StreamBinaryDeserializer<>(eventloop, intSerializer(), 10),
                    new StreamBinarySerializer<>(eventloop, intSerializer(), 2, 10, 0, false))
                .addHandler(
                    Integer.class,
                    new MessagingHandler<Integer, Integer>() {
                      @Override
                      public void onMessage(Integer item, Messaging<Integer> messaging) {
                        System.out.println(item);
                        messaging.sendMessage(item);
                      }
                    });
          }
        };
    server.setListenAddress(address).acceptOnce();
    server.listen();

    eventloop.connect(
        address,
        new SocketSettings(),
        new ConnectCallback() {
          @Override
          public void onConnect(SocketChannel socketChannel) {
            SocketConnection connection =
                new StreamMessagingConnection<>(
                        eventloop,
                        socketChannel,
                        new StreamBinaryDeserializer<>(eventloop, intSerializer(), 10),
                        new StreamBinarySerializer<>(eventloop, intSerializer(), 2, 10, 0, false))
                    .addStarter(
                        new MessagingStarter<Integer>() {
                          @Override
                          public void onStart(Messaging<Integer> messaging) {
                            messaging.sendMessage(3);
                          }
                        })
                    .addHandler(
                        Integer.class,
                        new MessagingHandler<Integer, Integer>() {
                          @Override
                          public void onMessage(Integer item, Messaging<Integer> messaging) {
                            if (item > 0) {
                              messaging.sendMessage(item - 1);
                            } else {
                              messaging.shutdown();
                            }
                          }
                        });
            connection.register();
          }

          @Override
          public void onException(Exception exception) {
            fail("Test Exception: " + exception);
          }
        });

    eventloop.run();

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }
  @Test
  public void testBinaryMessagingUploadAck() throws Exception {
    final List<Long> source = Lists.newArrayList();
    for (long i = 0; i < 100; i++) {
      source.add(i);
    }

    final AtomicBoolean ack = new AtomicBoolean(false);

    final NioEventloop eventloop = new NioEventloop();

    final StreamConsumers.ToList<Long> consumerToList = StreamConsumers.toList(eventloop);

    SimpleNioServer server =
        new SimpleNioServer(eventloop) {
          @Override
          protected SocketConnection createConnection(SocketChannel socketChannel) {
            return new StreamMessagingConnection<>(
                    eventloop,
                    socketChannel,
                    new StreamBinaryDeserializer<>(eventloop, stringSerializer(), 10),
                    new StreamBinarySerializer<>(eventloop, stringSerializer(), 2, 10, 0, false))
                .addHandler(
                    String.class,
                    new MessagingHandler<String, String>() {
                      @Override
                      public void onMessage(String item, final Messaging<String> messaging) {
                        assertEquals("start", item);
                        System.out.println("receive start");

                        StreamBinaryDeserializer<Long> streamDeserializer =
                            new StreamBinaryDeserializer<>(eventloop, longSerializer(), 10);
                        messaging.binarySocketReader().streamTo(streamDeserializer);
                        streamDeserializer.streamTo(consumerToList);

                        consumerToList.addCompletionCallback(
                            new CompletionCallback() {
                              @Override
                              public void onComplete() {
                                System.out.println("send ack");
                                messaging.sendMessage("ack");
                                messaging.shutdown();
                              }

                              @Override
                              public void onException(Exception exception) {
                                messaging.shutdown();
                              }
                            });
                      }
                    });
          }
        };
    server.setListenAddress(address).acceptOnce();
    server.listen();

    eventloop.connect(
        address,
        new SocketSettings(),
        new ConnectCallback() {
          @Override
          public void onConnect(SocketChannel socketChannel) {
            SocketConnection connection =
                new StreamMessagingConnection<>(
                        eventloop,
                        socketChannel,
                        new StreamBinaryDeserializer<>(eventloop, stringSerializer(), 10),
                        new StreamBinarySerializer<>(
                            eventloop, stringSerializer(), 2, 10, 0, false))
                    .addStarter(
                        new MessagingStarter<String>() {
                          @Override
                          public void onStart(Messaging<String> messaging) {
                            System.out.println("send start");
                            messaging.sendMessage("start");

                            StreamBinarySerializer<Long> streamSerializer =
                                new StreamBinarySerializer<>(
                                    eventloop, longSerializer(), 1, 10, 0, false);
                            StreamProducers.ofIterable(eventloop, source)
                                .streamTo(streamSerializer);
                            streamSerializer.streamTo(messaging.binarySocketWriter());
                          }
                        })
                    .addHandler(
                        String.class,
                        new MessagingHandler<String, String>() {
                          @Override
                          public void onMessage(String item, Messaging<String> messaging) {
                            ack.set(true);
                            assertEquals("ack", item);
                            System.out.println("receive ack");
                          }
                        });

            connection.register();
          }

          @Override
          public void onException(Exception e) {
            fail("Test Exception: " + e);
          }
        });

    eventloop.run();

    assertEquals(source, consumerToList.getList());
    assertTrue(ack.get());

    assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
  }