11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.collect.Iterables.getOnlyElement;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.util.concurrent.MoreExecutors.listeningDecorator;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.SECONDS;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static org.junit.contrib.truth.Truth.ASSERT;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Throwables;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableList;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Callable;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CyclicBarrier;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutorService;
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Future;
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.RejectedExecutionException;
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicReference;
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Tests for MoreExecutors.
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kyle Littlefield (klittle)
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class MoreExecutorsTest extends TestCase {
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSameThreadExecutorServiceInThreadExecution()
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throws Exception {
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final ListeningExecutorService executor =
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        MoreExecutors.sameThreadExecutor();
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected Integer initialValue() {
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final AtomicReference<Throwable> throwableFromOtherThread =
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new AtomicReference<Throwable>(null);
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Runnable incrementTask =
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new Runnable() {
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          @Override
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          public void run() {
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            threadLocalCount.set(threadLocalCount.get() + 1);
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        };
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Thread otherThread = new Thread(
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new Runnable() {
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          @Override
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          public void run() {
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            try {
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              Future<?> future = executor.submit(incrementTask);
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              assertTrue(future.isDone());
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              assertEquals(1, threadLocalCount.get().intValue());
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            } catch (Throwable Throwable) {
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              throwableFromOtherThread.set(Throwable);
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        });
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    otherThread.start();
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ListenableFuture<?> future = executor.submit(incrementTask);
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(future.isDone());
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertListenerRunImmediately(future);
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, threadLocalCount.get().intValue());
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    otherThread.join(1000);
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Thread.State.TERMINATED, otherThread.getState());
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Throwable throwable = throwableFromOtherThread.get();
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull("Throwable from other thread: "
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        + (throwable == null ? null : Throwables.getStackTraceAsString(throwable)),
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throwableFromOtherThread.get());
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSameThreadExecutorInvokeAll() throws Exception {
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final ExecutorService executor = MoreExecutors.sameThreadExecutor();
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected Integer initialValue() {
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Callable<Integer> incrementTask = new Callable<Integer>() {
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Integer call() {
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int i = threadLocalCount.get();
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        threadLocalCount.set(i + 1);
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return i;
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    List<Future<Integer>> futures =
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        executor.invokeAll(Collections.nCopies(10, incrementTask));
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < 10; i++) {
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Future<Integer> future = futures.get(i);
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue("Task should have been run before being returned", future.isDone());
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, future.get().intValue());
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(10, threadLocalCount.get().intValue());
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSameThreadExecutorServiceTermination()
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throws Exception {
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final ExecutorService executor = MoreExecutors.sameThreadExecutor();
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CyclicBarrier barrier = new CyclicBarrier(2);
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final AtomicReference<Throwable> throwableFromOtherThread =
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new AtomicReference<Throwable>(null);
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Runnable doNothingRunnable = new Runnable() {
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override public void run() {
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }};
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Thread otherThread = new Thread(new Runnable() {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void run() {
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          Future<?> future = executor.submit(new Callable<Void>() {
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            @Override
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            public Void call() throws Exception {
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              // WAIT #1
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              barrier.await(1, TimeUnit.SECONDS);
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              // WAIT #2
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              barrier.await(1, TimeUnit.SECONDS);
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              assertTrue(executor.isShutdown());
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              assertFalse(executor.isTerminated());
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              // WAIT #3
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              barrier.await(1, TimeUnit.SECONDS);
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return null;
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          });
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(future.isDone());
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(executor.isShutdown());
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(executor.isTerminated());
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (Throwable Throwable) {
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throwableFromOtherThread.set(Throwable);
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }});
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    otherThread.start();
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // WAIT #1
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    barrier.await(1, TimeUnit.SECONDS);
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(executor.isShutdown());
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(executor.isTerminated());
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executor.shutdown();
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(executor.isShutdown());
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      executor.submit(doNothingRunnable);
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail("Should have encountered RejectedExecutionException");
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (RejectedExecutionException ex) {
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // good to go
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(executor.isTerminated());
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // WAIT #2
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    barrier.await(1, TimeUnit.SECONDS);
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(executor.awaitTermination(20, TimeUnit.MILLISECONDS));
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // WAIT #3
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    barrier.await(1, TimeUnit.SECONDS);
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(executor.awaitTermination(1, TimeUnit.SECONDS));
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(executor.awaitTermination(0, TimeUnit.SECONDS));
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(executor.isShutdown());
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      executor.submit(doNothingRunnable);
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail("Should have encountered RejectedExecutionException");
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (RejectedExecutionException ex) {
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // good to go
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(executor.isTerminated());
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    otherThread.join(1000);
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Thread.State.TERMINATED, otherThread.getState());
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Throwable throwable = throwableFromOtherThread.get();
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull("Throwable from other thread: "
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        + (throwable == null ? null : Throwables.getStackTraceAsString(throwable)),
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throwableFromOtherThread.get());
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testListeningDecorator() throws Exception {
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ListeningExecutorService service =
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        listeningDecorator(MoreExecutors.sameThreadExecutor());
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(service, listeningDecorator(service));
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    List<Callable<String>> callables =
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ImmutableList.of(Callables.returning("x"));
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    List<Future<String>> results;
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    results = service.invokeAll(callables);
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ASSERT.that(getOnlyElement(results)).isA(ListenableFutureTask.class);
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    results = service.invokeAll(callables, 1, SECONDS);
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ASSERT.that(getOnlyElement(results)).isA(ListenableFutureTask.class);
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /*
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * TODO(cpovirk): move ForwardingTestCase somewhere common, and use it to
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * test the forwarded methods
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void assertListenerRunImmediately(ListenableFuture<?> future) {
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingRunnable listener = new CountingRunnable();
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    future.addListener(listener, sameThreadExecutor());
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, listener.count);
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class CountingRunnable implements Runnable {
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int count;
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void run() {
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      count++;
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
240