Пример #1
0
 private static void testPromiseListenerAddWhenComplete(Throwable cause)
     throws InterruptedException {
   final CountDownLatch latch = new CountDownLatch(1);
   final Promise<Void> promise = new DefaultPromise<Void>(ImmediateEventExecutor.INSTANCE);
   promise.addListener(
       new FutureListener<Void>() {
         @Override
         public void operationComplete(Future<Void> future) throws Exception {
           promise.addListener(
               new FutureListener<Void>() {
                 @Override
                 public void operationComplete(Future<Void> future) throws Exception {
                   latch.countDown();
                 }
               });
         }
       });
   if (cause == null) {
     promise.setSuccess(null);
   } else {
     promise.setFailure(cause);
   }
   latch.await();
 }
Пример #2
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();
    }
  }