/**
   * Expect ExecutionTimedOutException because we only have 1 thread, try to execute 2 tasks, each
   * is only allowed 10ms of execution time
   *
   * @throws RejectedExecutionException
   * @throws InterruptedException
   */
  public void testExecuteBlockingFail() throws RejectedExecutionException, InterruptedException {

    JBossThreadFactory threadFactory =
        new JBossThreadFactory(null, null, null, "test thread %p %t", null, null);

    int cpuCount = Runtime.getRuntime().availableProcessors();
    int maxThreadNo = 1;
    final CountDownLatch taskUnfreezer = new CountDownLatch(1);
    final CountDownLatch taskFinishLine = new CountDownLatch(maxThreadNo);

    final ExecutorService handoffExec = Executors.newFixedThreadPool(cpuCount);
    final QueuelessExecutor queuelessExec =
        new QueuelessExecutor(threadFactory, JBossExecutors.directExecutor(), null, 2000);
    queuelessExec.setHandoffExecutor(handoffExec);
    queuelessExec.setKeepAliveTime(2000);
    queuelessExec.setMaxThreads(maxThreadNo);
    queuelessExec.setBlocking(false);

    final CountDownLatch finishLatch2 = new CountDownLatch(1);
    queuelessExec.setBlocking(true);

    final int threadNo3 = 777;
    queuelessExec.executeBlocking(
        new Runnable() {
          @Override
          public void run() {
            for (int j = 0; j < 50000000; j++) {
              int k = j * j * j;
              k = k * k * k * k * k * k;
            }
            System.out.println("Thread  : " + threadNo3 + " running inside queuelessExecutor");
            System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
            finishLatch2.countDown();
          }
        },
        10L,
        TimeUnit.MILLISECONDS);

    try {
      queuelessExec.executeBlocking(
          new Runnable() {
            @Override
            public void run() {
              for (int j = 0; j < 50000000; j++) {
                int k = j * j * j;
                k = k * k * k * k * k * k;
              }
              System.out.println("Thread  : " + threadNo3 + " running inside queuelessExecutor");
              System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
              finishLatch2.countDown();
            }
          },
          10L,
          TimeUnit.MILLISECONDS);
    } catch (ExecutionTimedOutException etoe) {
      System.out.println("Timed out....");
    }
  }
  public void testExecuteNonBlockingNullThread() {
    ThreadFactory nullFactory =
        new ThreadFactory() {
          @Override
          public Thread newThread(Runnable r) {
            return null;
          }
        };

    int cpuCount = Runtime.getRuntime().availableProcessors();
    int maxThreadNo = 1;
    final CountDownLatch taskUnfreezer = new CountDownLatch(1);
    final CountDownLatch taskFinishLine = new CountDownLatch(maxThreadNo);

    final ExecutorService handoffExec = Executors.newFixedThreadPool(cpuCount);
    final QueuelessExecutor queuelessExec =
        new QueuelessExecutor(nullFactory, JBossExecutors.directExecutor(), null, 2000);
    queuelessExec.setHandoffExecutor(handoffExec);
    queuelessExec.setKeepAliveTime(2000);
    queuelessExec.setMaxThreads(maxThreadNo);
    queuelessExec.setBlocking(false);

    final CountDownLatch finishLatch2 = new CountDownLatch(1);
    queuelessExec.setBlocking(true);

    final int threadNo = 111;

    try {
      queuelessExec.executeNonBlocking(
          new Runnable() {
            @Override
            public void run() {
              for (int j = 0; j < 50000000; j++) {
                int k = j * j * j;
                k = k * k * k * k * k * k;
              }
              System.out.println("Thread  : " + threadNo + " running inside queuelessExecutor");
              System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
              finishLatch2.countDown();
            }
          });
    } catch (ThreadCreationException tce) {
      System.out.println("Expecting ThreadCreationException and getting it.");
    }
  }
  public void testExecuteNonBlocking() {

    JBossThreadFactory threadFactory =
        new JBossThreadFactory(null, null, null, "test thread %p %t", null, null);

    int cpuCount = Runtime.getRuntime().availableProcessors();
    int maxThreadNo = 1;
    final CountDownLatch taskUnfreezer = new CountDownLatch(1);
    final CountDownLatch taskFinishLine = new CountDownLatch(maxThreadNo);

    final ExecutorService handoffExec = Executors.newFixedThreadPool(cpuCount);
    final QueuelessExecutor queuelessExec =
        new QueuelessExecutor(threadFactory, JBossExecutors.directExecutor(), null, 2000);
    queuelessExec.setHandoffExecutor(handoffExec);
    queuelessExec.setKeepAliveTime(2000);
    queuelessExec.setMaxThreads(maxThreadNo);
    queuelessExec.setBlocking(false);

    final CountDownLatch finishLatch2 = new CountDownLatch(1);
    queuelessExec.setBlocking(true);

    final int threadNo = 111;
    queuelessExec.executeNonBlocking(
        new Runnable() {
          @Override
          public void run() {
            for (int j = 0; j < 50000000; j++) {
              int k = j * j * j;
              k = k * k * k * k * k * k;
            }
            System.out.println("Thread  : " + threadNo + " running inside queuelessExecutor");
            System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
            finishLatch2.countDown();
          }
        });
  }
  public void testBasic() throws InterruptedException {
    JBossThreadFactory threadFactory =
        new JBossThreadFactory(null, null, null, "test thread %p %t", null, null);

    int cpuCount = Runtime.getRuntime().availableProcessors();
    int maxThreadNo = cpuCount * 2;
    final CountDownLatch taskUnfreezer = new CountDownLatch(1);
    final CountDownLatch taskFinishLine = new CountDownLatch(maxThreadNo);

    final ExecutorService handoffExec = Executors.newFixedThreadPool(cpuCount);
    final QueuelessExecutor queuelessExec =
        new QueuelessExecutor(threadFactory, JBossExecutors.directExecutor(), null, 2000);
    queuelessExec.setHandoffExecutor(handoffExec);
    queuelessExec.setKeepAliveTime(2000);
    queuelessExec.setMaxThreads(maxThreadNo);
    queuelessExec.setBlocking(false);

    for (int i = 0; i < maxThreadNo; i++) {
      final int threadNo = i;
      queuelessExec.execute(
          new Runnable() {
            @Override
            public void run() {
              try {
                taskUnfreezer.await();
                for (int j = 0; j < 5000000; j++) {
                  int k = j * j * j;
                  k = k * k * k * k * k * k;
                }
                System.out.println(
                    "Thread " /*+  Thread.currentThread().getId() */
                        + " : "
                        + threadNo
                        + " running inside queuelessExecutor");
                System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());

                taskFinishLine.countDown();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          });
    }

    long start = System.nanoTime();
    taskUnfreezer.countDown();

    taskFinishLine.await(1112000L, TimeUnit.MILLISECONDS);
    long end = System.nanoTime();

    System.out.println((end - start) / 1000000);

    assertTrue(queuelessExec.getCurrentThreadCount() == maxThreadNo);
    assertTrue(queuelessExec.getHandoffExecutor() == handoffExec);
    assertTrue(queuelessExec.getMaxThreads() == maxThreadNo);
    assertTrue(queuelessExec.getLargestThreadCount() == maxThreadNo);
    assertTrue(queuelessExec.getKeepAliveTime() == 2000);
    assertTrue(queuelessExec.getRejectedCount() == 0);
    assertFalse(queuelessExec.isBlocking());

    /////////////////////////
    // executeBlocking
    /////////////////////////
    final CountDownLatch finishLatch = new CountDownLatch(1);
    queuelessExec.setBlocking(true);
    final int threadNo = 999;
    queuelessExec.executeBlocking(
        new Runnable() {
          @Override
          public void run() {
            for (int j = 0; j < 500000; j++) {
              int k = j * j * j;
              k = k * k * k * k * k * k;
            }
            System.out.println("Thread  : " + threadNo + " running inside queuelessExecutor");
            System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
            finishLatch.countDown();
          }
        });
    finishLatch.await();

    /////////////////////////////////////
    // executeBlocking(... , ... , ... )
    /////////////////////////////////////

    final CountDownLatch finishLatch2 = new CountDownLatch(1);
    queuelessExec.setBlocking(true);
    final int threadNo2 = 888;
    queuelessExec.executeBlocking(
        new Runnable() {
          @Override
          public void run() {
            for (int j = 0; j < 50000000; j++) {
              int k = j * j * j;
              k = k * k * k * k * k * k;
            }
            System.out.println("Thread  : " + threadNo2 + " running inside queuelessExecutor");
            System.out.println("Thread count: " + queuelessExec.getCurrentThreadCount());
            finishLatch2.countDown();
          }
        },
        10L,
        TimeUnit.MILLISECONDS);

    finishLatch2.await();

    ///////////////
    // shutting down
    /////////////////

    queuelessExec.shutdown();
    queuelessExec.awaitTermination(2000, TimeUnit.MILLISECONDS);
    List<Runnable> neverRunTask = queuelessExec.shutdownNow();
    assertTrue("all tasks should've been executed", neverRunTask.size() == 0);
    assertTrue(queuelessExec.isShutdown());

    if (!queuelessExec.isTerminated()) {
      queuelessExec.shutdownNow();
    }

    // assertTrue(queuelessExec.isTerminated());
  }