Example #1
0
  @Test
  public void testListenerNotifyOrder() throws Exception {
    EventExecutor executor = new TestEventExecutor();
    try {
      final BlockingQueue<FutureListener<Void>> listeners =
          new LinkedBlockingQueue<FutureListener<Void>>();
      int runs = 100000;

      for (int i = 0; i < runs; i++) {
        final Promise<Void> promise = new DefaultPromise<Void>(executor);
        final FutureListener<Void> listener1 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener2 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener4 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
              }
            };
        final FutureListener<Void> listener3 =
            new FutureListener<Void>() {
              @Override
              public void operationComplete(Future<Void> future) throws Exception {
                listeners.add(this);
                future.addListener(listener4);
              }
            };

        GlobalEventExecutor.INSTANCE.execute(
            new Runnable() {
              @Override
              public void run() {
                promise.setSuccess(null);
              }
            });

        promise.addListener(listener1).addListener(listener2).addListener(listener3);

        assertSame("Fail 1 during run " + i + " / " + runs, listener1, listeners.take());
        assertSame("Fail 2 during run " + i + " / " + runs, listener2, listeners.take());
        assertSame("Fail 3 during run " + i + " / " + runs, listener3, listeners.take());
        assertSame("Fail 4 during run " + i + " / " + runs, listener4, listeners.take());
        assertTrue("Fail during run " + i + " / " + runs, listeners.isEmpty());
      }
    } finally {
      executor.shutdownGracefully(0, 0, TimeUnit.SECONDS).sync();
    }
  }
 private EventExecutor getWrappedExecutor(final EventExecutor executor) {
   return (listener, event) -> {
     // Just like above
     try {
       executor.execute(listener, event);
     } catch (AuthorNagException e) {
       throw e;
     } catch (Throwable e) {
       customHandler(event, e);
     }
   };
 }
Example #3
0
  private static void testListenerNotifyLater(final int numListenersBefore) throws Exception {
    EventExecutor executor = new TestEventExecutor();
    int expectedCount = numListenersBefore + 2;
    final CountDownLatch latch = new CountDownLatch(expectedCount);
    final FutureListener<Void> listener =
        new FutureListener<Void>() {
          @Override
          public void operationComplete(Future<Void> future) throws Exception {
            latch.countDown();
          }
        };
    final Promise<Void> promise = new DefaultPromise<Void>(executor);
    executor.execute(
        new Runnable() {
          @Override
          public void run() {
            for (int i = 0; i < numListenersBefore; i++) {
              promise.addListener(listener);
            }
            promise.setSuccess(null);

            GlobalEventExecutor.INSTANCE.execute(
                new Runnable() {
                  @Override
                  public void run() {
                    promise.addListener(listener);
                  }
                });
            promise.addListener(listener);
          }
        });

    assertTrue(
        "Should have notifed " + expectedCount + " listeners", latch.await(5, TimeUnit.SECONDS));
    executor.shutdownGracefully().sync();
  }
Example #4
0
  /**
   * This test is mean to simulate the following sequence of events, which all take place on the I/O
   * thread:
   *
   * <ol>
   *   <li>A write is done
   *   <li>The write operation completes, and the promise state is changed to done
   *   <li>A listener is added to the return from the write. The {@link
   *       FutureListener#operationComplete()} updates state which must be invoked before the
   *       response to the previous write is read.
   *   <li>The write operation
   * </ol>
   */
  private static void testLateListenerIsOrderedCorrectly(Throwable cause)
      throws InterruptedException {
    final EventExecutor executor = new TestEventExecutor();
    try {
      final AtomicInteger state = new AtomicInteger();
      final CountDownLatch latch1 = new CountDownLatch(1);
      final CountDownLatch latch2 = new CountDownLatch(2);
      final Promise<Void> promise = new DefaultPromise<Void>(executor);

      // Add a listener before completion so "lateListener" is used next time we add a listener.
      promise.addListener(
          new FutureListener<Void>() {
            @Override
            public void operationComplete(Future<Void> future) throws Exception {
              assertTrue(state.compareAndSet(0, 1));
            }
          });

      // Simulate write operation completing, which will execute listeners in another thread.
      if (cause == null) {
        promise.setSuccess(null);
      } else {
        promise.setFailure(cause);
      }

      // Add a "late listener"
      promise.addListener(
          new FutureListener<Void>() {
            @Override
            public void operationComplete(Future<Void> future) throws Exception {
              assertTrue(state.compareAndSet(1, 2));
              latch1.countDown();
            }
          });

      // Wait for the listeners and late listeners to be completed.
      latch1.await();
      assertEquals(2, state.get());

      // This is the important listener. A late listener that is added after all late listeners
      // have completed, and needs to update state before a read operation (on the same executor).
      executor.execute(
          new Runnable() {
            @Override
            public void run() {
              promise.addListener(
                  new FutureListener<Void>() {
                    @Override
                    public void operationComplete(Future<Void> future) throws Exception {
                      assertTrue(state.compareAndSet(2, 3));
                      latch2.countDown();
                    }
                  });
            }
          });

      // Simulate a read operation being queued up in the executor.
      executor.execute(
          new Runnable() {
            @Override
            public void run() {
              // This is the key, we depend upon the state being set in the next listener.
              assertEquals(3, state.get());
              latch2.countDown();
            }
          });

      latch2.await();
    } finally {
      executor.shutdownGracefully(0, 0, TimeUnit.SECONDS).sync();
    }
  }