Home | History | Annotate | Download | only in concurrent
      1 /*
      2  * Copyright (C) 2008 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * Portions of this file are modified versions of
     19  * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30
     20  * which contained the following notice:
     21  *
     22  * Written by Doug Lea with assistance from members of JCP JSR-166
     23  * Expert Group and released to the public domain, as explained at
     24  * http://creativecommons.org/publicdomain/zero/1.0/
     25  * Other contributors include Andrew Wright, Jeffrey Hayes,
     26  * Pat Fisher, Mike Judd.
     27  */
     28 
     29 package com.google.common.util.concurrent;
     30 
     31 import static com.google.common.collect.Iterables.getOnlyElement;
     32 import static com.google.common.truth.Truth.assertThat;
     33 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
     34 import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
     35 import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator;
     36 import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
     37 import static com.google.common.util.concurrent.MoreExecutors.renamingDecorator;
     38 import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination;
     39 import static java.util.concurrent.TimeUnit.NANOSECONDS;
     40 import static java.util.concurrent.TimeUnit.SECONDS;
     41 import static org.mockito.Mockito.mock;
     42 import static org.mockito.Mockito.times;
     43 import static org.mockito.Mockito.verify;
     44 import static org.mockito.Mockito.when;
     45 
     46 import com.google.common.base.Suppliers;
     47 import com.google.common.base.Throwables;
     48 import com.google.common.collect.ImmutableList;
     49 import com.google.common.collect.Lists;
     50 import com.google.common.testing.ClassSanityTester;
     51 import com.google.common.util.concurrent.MoreExecutors.Application;
     52 
     53 import org.mockito.InOrder;
     54 import org.mockito.Mockito;
     55 
     56 import java.util.ArrayList;
     57 import java.util.Collections;
     58 import java.util.List;
     59 import java.util.concurrent.ArrayBlockingQueue;
     60 import java.util.concurrent.BlockingQueue;
     61 import java.util.concurrent.Callable;
     62 import java.util.concurrent.CountDownLatch;
     63 import java.util.concurrent.CyclicBarrier;
     64 import java.util.concurrent.ExecutionException;
     65 import java.util.concurrent.Executor;
     66 import java.util.concurrent.ExecutorService;
     67 import java.util.concurrent.Executors;
     68 import java.util.concurrent.Future;
     69 import java.util.concurrent.RejectedExecutionException;
     70 import java.util.concurrent.ScheduledFuture;
     71 import java.util.concurrent.ScheduledThreadPoolExecutor;
     72 import java.util.concurrent.ThreadFactory;
     73 import java.util.concurrent.ThreadPoolExecutor;
     74 import java.util.concurrent.TimeUnit;
     75 import java.util.concurrent.atomic.AtomicBoolean;
     76 import java.util.concurrent.atomic.AtomicReference;
     77 
     78 /**
     79  * Tests for MoreExecutors.
     80  *
     81  * @author Kyle Littlefield (klittle)
     82  */
     83 public class MoreExecutorsTest extends JSR166TestCase {
     84 
     85   private static final Runnable EMPTY_RUNNABLE = new Runnable() {
     86     @Override public void run() {}
     87   };
     88 
     89   public void testDirectExecutorServiceServiceInThreadExecution()
     90       throws Exception {
     91     final ListeningExecutorService executor = newDirectExecutorService();
     92     final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
     93       @Override
     94       protected Integer initialValue() {
     95         return 0;
     96       }
     97     };
     98     final AtomicReference<Throwable> throwableFromOtherThread =
     99         new AtomicReference<Throwable>(null);
    100     final Runnable incrementTask =
    101         new Runnable() {
    102           @Override
    103           public void run() {
    104             threadLocalCount.set(threadLocalCount.get() + 1);
    105           }
    106         };
    107 
    108     Thread otherThread = new Thread(
    109         new Runnable() {
    110           @Override
    111           public void run() {
    112             try {
    113               Future<?> future = executor.submit(incrementTask);
    114               assertTrue(future.isDone());
    115               assertEquals(1, threadLocalCount.get().intValue());
    116             } catch (Throwable t) {
    117               throwableFromOtherThread.set(t);
    118             }
    119           }
    120         });
    121 
    122     otherThread.start();
    123 
    124     ListenableFuture<?> future = executor.submit(incrementTask);
    125     assertTrue(future.isDone());
    126     assertListenerRunImmediately(future);
    127     assertEquals(1, threadLocalCount.get().intValue());
    128     otherThread.join(1000);
    129     assertEquals(Thread.State.TERMINATED, otherThread.getState());
    130     Throwable throwable = throwableFromOtherThread.get();
    131     assertNull("Throwable from other thread: "
    132         + (throwable == null ? null : Throwables.getStackTraceAsString(throwable)),
    133         throwableFromOtherThread.get());
    134   }
    135 
    136   public void testDirectExecutorServiceInvokeAll() throws Exception {
    137     final ExecutorService executor = newDirectExecutorService();
    138     final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
    139       @Override
    140       protected Integer initialValue() {
    141         return 0;
    142       }
    143     };
    144 
    145     final Callable<Integer> incrementTask = new Callable<Integer>() {
    146       @Override
    147       public Integer call() {
    148         int i = threadLocalCount.get();
    149         threadLocalCount.set(i + 1);
    150         return i;
    151       }
    152     };
    153 
    154     List<Future<Integer>> futures =
    155         executor.invokeAll(Collections.nCopies(10, incrementTask));
    156 
    157     for (int i = 0; i < 10; i++) {
    158       Future<Integer> future = futures.get(i);
    159       assertTrue("Task should have been run before being returned", future.isDone());
    160       assertEquals(i, future.get().intValue());
    161     }
    162 
    163     assertEquals(10, threadLocalCount.get().intValue());
    164   }
    165 
    166   public void testDirectExecutorServiceServiceTermination()
    167       throws Exception {
    168     final ExecutorService executor = newDirectExecutorService();
    169     final CyclicBarrier barrier = new CyclicBarrier(2);
    170     final AtomicReference<Throwable> throwableFromOtherThread =
    171         new AtomicReference<Throwable>(null);
    172     final Runnable doNothingRunnable = new Runnable() {
    173         @Override public void run() {
    174         }};
    175 
    176     Thread otherThread = new Thread(new Runnable() {
    177       @Override
    178       public void run() {
    179         try {
    180           Future<?> future = executor.submit(new Callable<Void>() {
    181             @Override
    182             public Void call() throws Exception {
    183               // WAIT #1
    184               barrier.await(1, TimeUnit.SECONDS);
    185 
    186               // WAIT #2
    187               barrier.await(1, TimeUnit.SECONDS);
    188               assertTrue(executor.isShutdown());
    189               assertFalse(executor.isTerminated());
    190 
    191               // WAIT #3
    192               barrier.await(1, TimeUnit.SECONDS);
    193               return null;
    194             }
    195           });
    196           assertTrue(future.isDone());
    197           assertTrue(executor.isShutdown());
    198           assertTrue(executor.isTerminated());
    199         } catch (Throwable t) {
    200           throwableFromOtherThread.set(t);
    201         }
    202       }});
    203 
    204     otherThread.start();
    205 
    206     // WAIT #1
    207     barrier.await(1, TimeUnit.SECONDS);
    208     assertFalse(executor.isShutdown());
    209     assertFalse(executor.isTerminated());
    210 
    211     executor.shutdown();
    212     assertTrue(executor.isShutdown());
    213     try {
    214       executor.submit(doNothingRunnable);
    215       fail("Should have encountered RejectedExecutionException");
    216     } catch (RejectedExecutionException ex) {
    217       // good to go
    218     }
    219     assertFalse(executor.isTerminated());
    220 
    221     // WAIT #2
    222     barrier.await(1, TimeUnit.SECONDS);
    223     assertFalse(executor.awaitTermination(20, TimeUnit.MILLISECONDS));
    224 
    225     // WAIT #3
    226     barrier.await(1, TimeUnit.SECONDS);
    227     assertTrue(executor.awaitTermination(1, TimeUnit.SECONDS));
    228     assertTrue(executor.awaitTermination(0, TimeUnit.SECONDS));
    229     assertTrue(executor.isShutdown());
    230     try {
    231       executor.submit(doNothingRunnable);
    232       fail("Should have encountered RejectedExecutionException");
    233     } catch (RejectedExecutionException ex) {
    234       // good to go
    235     }
    236     assertTrue(executor.isTerminated());
    237 
    238     otherThread.join(1000);
    239     assertEquals(Thread.State.TERMINATED, otherThread.getState());
    240     Throwable throwable = throwableFromOtherThread.get();
    241     assertNull("Throwable from other thread: "
    242         + (throwable == null ? null : Throwables.getStackTraceAsString(throwable)),
    243         throwableFromOtherThread.get());
    244   }
    245 
    246   public void testDirectExecutorService_shutdownNow() {
    247     ExecutorService executor = newDirectExecutorService();
    248     assertEquals(ImmutableList.of(), executor.shutdownNow());
    249     assertTrue(executor.isShutdown());
    250   }
    251 
    252   public void testExecuteAfterShutdown() {
    253     ExecutorService executor = newDirectExecutorService();
    254     executor.shutdown();
    255     try {
    256       executor.execute(EMPTY_RUNNABLE);
    257       fail();
    258     } catch (RejectedExecutionException expected) {}
    259   }
    260 
    261   public <T> void testListeningExecutorServiceInvokeAllJavadocCodeCompiles()
    262       throws Exception {
    263     ListeningExecutorService executor = newDirectExecutorService();
    264     List<Callable<T>> tasks = ImmutableList.of();
    265     @SuppressWarnings("unchecked") // guaranteed by invokeAll contract
    266     List<ListenableFuture<T>> futures = (List) executor.invokeAll(tasks);
    267   }
    268 
    269   public void testListeningDecorator() throws Exception {
    270     ListeningExecutorService service =
    271         listeningDecorator(newDirectExecutorService());
    272     assertSame(service, listeningDecorator(service));
    273     List<Callable<String>> callables =
    274         ImmutableList.of(Callables.returning("x"));
    275     List<Future<String>> results;
    276 
    277     results = service.invokeAll(callables);
    278     assertThat(getOnlyElement(results)).isA(ListenableFutureTask.class);
    279 
    280     results = service.invokeAll(callables, 1, SECONDS);
    281     assertThat(getOnlyElement(results)).isA(ListenableFutureTask.class);
    282 
    283     /*
    284      * TODO(cpovirk): move ForwardingTestCase somewhere common, and use it to
    285      * test the forwarded methods
    286      */
    287   }
    288 
    289   public void testListeningDecorator_noWrapExecuteTask() {
    290     ExecutorService delegate = mock(ExecutorService.class);
    291     ListeningExecutorService service = listeningDecorator(delegate);
    292     Runnable task = new Runnable() {
    293       @Override
    294       public void run() {}
    295     };
    296     service.execute(task);
    297     verify(delegate).execute(task);
    298   }
    299 
    300   public void testListeningDecorator_scheduleSuccess() throws Exception {
    301     final CountDownLatch completed = new CountDownLatch(1);
    302     ScheduledThreadPoolExecutor delegate = new ScheduledThreadPoolExecutor(1) {
    303       @Override
    304       protected void afterExecute(Runnable r, Throwable t) {
    305         completed.countDown();
    306       }
    307     };
    308     ListeningScheduledExecutorService service = listeningDecorator(delegate);
    309     ListenableFuture<?> future =
    310         service.schedule(Callables.returning(null), 1, TimeUnit.MILLISECONDS);
    311 
    312     /*
    313      * Wait not just until the Future's value is set (as in future.get()) but
    314      * also until ListeningScheduledExecutorService's wrapper task is done
    315      * executing listeners, as detected by yielding control to afterExecute.
    316      */
    317     completed.await();
    318     assertTrue(future.isDone());
    319     assertListenerRunImmediately(future);
    320     assertEquals(0, delegate.getQueue().size());
    321   }
    322 
    323   public void testListeningDecorator_scheduleFailure() throws Exception {
    324     ScheduledThreadPoolExecutor delegate = new ScheduledThreadPoolExecutor(1);
    325     ListeningScheduledExecutorService service = listeningDecorator(delegate);
    326     RuntimeException ex = new RuntimeException();
    327     ListenableFuture<?> future =
    328         service.schedule(new ThrowingRunnable(0, ex), 1, TimeUnit.MILLISECONDS);
    329     assertExecutionException(future, ex);
    330     assertEquals(0, delegate.getQueue().size());
    331   }
    332 
    333   public void testListeningDecorator_schedulePeriodic() throws Exception {
    334     ScheduledThreadPoolExecutor delegate = new ScheduledThreadPoolExecutor(1);
    335     ListeningScheduledExecutorService service = listeningDecorator(delegate);
    336     RuntimeException ex = new RuntimeException();
    337 
    338     ListenableFuture<?> future;
    339 
    340     ThrowingRunnable runnable = new ThrowingRunnable(5, ex);
    341     future = service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.MILLISECONDS);
    342     assertExecutionException(future, ex);
    343     assertEquals(5, runnable.count);
    344     assertEquals(0, delegate.getQueue().size());
    345 
    346     runnable = new ThrowingRunnable(5, ex);
    347     future = service.scheduleWithFixedDelay(runnable, 1, 1, TimeUnit.MILLISECONDS);
    348     assertExecutionException(future, ex);
    349     assertEquals(5, runnable.count);
    350     assertEquals(0, delegate.getQueue().size());
    351   }
    352 
    353   public void testListeningDecorator_cancelled() throws Exception {
    354     ScheduledThreadPoolExecutor delegate = new ScheduledThreadPoolExecutor(1);
    355     BlockingQueue<?> delegateQueue = delegate.getQueue();
    356     ListeningScheduledExecutorService service = listeningDecorator(delegate);
    357     ListenableFuture<?> future;
    358     ScheduledFuture<?> delegateFuture;
    359 
    360     Runnable runnable = new Runnable() {
    361       @Override public void run() {}
    362     };
    363 
    364     future = service.schedule(runnable, 5, TimeUnit.MINUTES);
    365     future.cancel(true);
    366     assertTrue(future.isCancelled());
    367     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
    368     assertTrue(delegateFuture.isCancelled());
    369 
    370     delegateQueue.clear();
    371 
    372     future = service.scheduleAtFixedRate(runnable, 5, 5, TimeUnit.MINUTES);
    373     future.cancel(true);
    374     assertTrue(future.isCancelled());
    375     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
    376     assertTrue(delegateFuture.isCancelled());
    377 
    378     delegateQueue.clear();
    379 
    380     future = service.scheduleWithFixedDelay(runnable, 5, 5, TimeUnit.MINUTES);
    381     future.cancel(true);
    382     assertTrue(future.isCancelled());
    383     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
    384     assertTrue(delegateFuture.isCancelled());
    385   }
    386 
    387   private static final class ThrowingRunnable implements Runnable {
    388     final int throwAfterCount;
    389     final RuntimeException thrown;
    390     int count;
    391 
    392     ThrowingRunnable(int throwAfterCount, RuntimeException thrown) {
    393       this.throwAfterCount = throwAfterCount;
    394       this.thrown = thrown;
    395     }
    396 
    397     @Override
    398     public void run() {
    399       if (++count >= throwAfterCount) {
    400         throw thrown;
    401       }
    402     }
    403   }
    404 
    405   private static void assertExecutionException(Future<?> future, Exception expectedCause)
    406       throws Exception {
    407     try {
    408       future.get();
    409       fail("Expected ExecutionException");
    410     } catch (ExecutionException e) {
    411       assertSame(expectedCause, e.getCause());
    412     }
    413   }
    414 
    415   /**
    416    * invokeAny(null) throws NPE
    417    */
    418   public void testInvokeAnyImpl_nullTasks() throws Exception {
    419     ListeningExecutorService e = newDirectExecutorService();
    420     try {
    421       invokeAnyImpl(e, null, false, 0);
    422       shouldThrow();
    423     } catch (NullPointerException success) {
    424     } finally {
    425       joinPool(e);
    426     }
    427   }
    428 
    429   /**
    430    * invokeAny(empty collection) throws IAE
    431    */
    432   public void testInvokeAnyImpl_emptyTasks() throws Exception {
    433     ListeningExecutorService e = newDirectExecutorService();
    434     try {
    435       invokeAnyImpl(e, new ArrayList<Callable<String>>(), false, 0);
    436       shouldThrow();
    437     } catch (IllegalArgumentException success) {
    438     } finally {
    439       joinPool(e);
    440     }
    441   }
    442 
    443   /**
    444    * invokeAny(c) throws NPE if c has null elements
    445    */
    446   public void testInvokeAnyImpl_nullElement() throws Exception {
    447     ListeningExecutorService e = newDirectExecutorService();
    448     List<Callable<Integer>> l = new ArrayList<Callable<Integer>>();
    449     l.add(new Callable<Integer>() {
    450       @Override public Integer call() {
    451           throw new ArithmeticException("/ by zero");
    452       }
    453     });
    454     l.add(null);
    455     try {
    456       invokeAnyImpl(e, l, false, 0);
    457       shouldThrow();
    458     } catch (NullPointerException success) {
    459     } finally {
    460       joinPool(e);
    461     }
    462   }
    463 
    464   /**
    465    * invokeAny(c) throws ExecutionException if no task in c completes
    466    */
    467   public void testInvokeAnyImpl_noTaskCompletes() throws Exception {
    468     ListeningExecutorService e = newDirectExecutorService();
    469     List<Callable<String>> l = new ArrayList<Callable<String>>();
    470     l.add(new NPETask());
    471     try {
    472       invokeAnyImpl(e, l, false, 0);
    473       shouldThrow();
    474     } catch (ExecutionException success) {
    475       assertTrue(success.getCause() instanceof NullPointerException);
    476     } finally {
    477       joinPool(e);
    478     }
    479   }
    480 
    481   /**
    482    * invokeAny(c) returns result of some task in c if at least one completes
    483    */
    484   public void testInvokeAnyImpl() throws Exception {
    485     ListeningExecutorService e = newDirectExecutorService();
    486     try {
    487       List<Callable<String>> l = new ArrayList<Callable<String>>();
    488       l.add(new StringTask());
    489       l.add(new StringTask());
    490       String result = invokeAnyImpl(e, l, false, 0);
    491       assertSame(TEST_STRING, result);
    492     } finally {
    493       joinPool(e);
    494     }
    495   }
    496 
    497   private static void assertListenerRunImmediately(ListenableFuture<?> future) {
    498     CountingRunnable listener = new CountingRunnable();
    499     future.addListener(listener, directExecutor());
    500     assertEquals(1, listener.count);
    501   }
    502 
    503   private static final class CountingRunnable implements Runnable {
    504     int count;
    505 
    506     @Override
    507     public void run() {
    508       count++;
    509     }
    510   }
    511 
    512   public void testAddDelayedShutdownHook_success() throws InterruptedException {
    513     TestApplication application = new TestApplication();
    514     ExecutorService service = mock(ExecutorService.class);
    515     application.addDelayedShutdownHook(service, 2, TimeUnit.SECONDS);
    516     verify(service, Mockito.never()).shutdown();
    517     application.shutdown();
    518     InOrder shutdownFirst = Mockito.inOrder(service);
    519     shutdownFirst.verify(service).shutdown();
    520     shutdownFirst.verify(service).awaitTermination(2, TimeUnit.SECONDS);
    521   }
    522 
    523   public void testAddDelayedShutdownHook_interrupted() throws InterruptedException {
    524     TestApplication application = new TestApplication();
    525     ExecutorService service = mock(ExecutorService.class);
    526     application.addDelayedShutdownHook(service, 2, TimeUnit.SECONDS);
    527     when(service.awaitTermination(2, TimeUnit.SECONDS)).thenThrow(new InterruptedException());
    528     application.shutdown();
    529     verify(service).shutdown();
    530   }
    531 
    532   public void testGetExitingExcutorService_executorSetToUseDaemonThreads() {
    533     TestApplication application = new TestApplication();
    534     ThreadPoolExecutor executor = new ThreadPoolExecutor(
    535         1, 2, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
    536     assertNotNull(application.getExitingExecutorService(executor));
    537     assertTrue(executor.getThreadFactory().newThread(EMPTY_RUNNABLE).isDaemon());
    538   }
    539 
    540   public void testGetExitingExcutorService_executorDelegatesToOriginal() {
    541     TestApplication application = new TestApplication();
    542     ThreadPoolExecutor executor = mock(ThreadPoolExecutor.class);
    543     ThreadFactory threadFactory = mock(ThreadFactory.class);
    544     when(executor.getThreadFactory()).thenReturn(threadFactory);
    545     application.getExitingExecutorService(executor).execute(EMPTY_RUNNABLE);
    546     verify(executor).execute(EMPTY_RUNNABLE);
    547   }
    548 
    549   public void testGetExitingExcutorService_shutdownHookRegistered() throws InterruptedException {
    550     TestApplication application = new TestApplication();
    551     ThreadPoolExecutor executor = mock(ThreadPoolExecutor.class);
    552     ThreadFactory threadFactory = mock(ThreadFactory.class);
    553     when(executor.getThreadFactory()).thenReturn(threadFactory);
    554     application.getExitingExecutorService(executor);
    555     application.shutdown();
    556     verify(executor).shutdown();
    557   }
    558 
    559   public void testGetExitingScheduledExcutorService_executorSetToUseDaemonThreads() {
    560     TestApplication application = new TestApplication();
    561     ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
    562     assertNotNull(application.getExitingScheduledExecutorService(executor));
    563     assertTrue(executor.getThreadFactory().newThread(EMPTY_RUNNABLE).isDaemon());
    564   }
    565 
    566   public void testGetExitingScheduledExcutorService_executorDelegatesToOriginal() {
    567     TestApplication application = new TestApplication();
    568     ScheduledThreadPoolExecutor executor = mock(ScheduledThreadPoolExecutor.class);
    569     ThreadFactory threadFactory = mock(ThreadFactory.class);
    570     when(executor.getThreadFactory()).thenReturn(threadFactory);
    571     application.getExitingScheduledExecutorService(executor).execute(EMPTY_RUNNABLE);
    572     verify(executor).execute(EMPTY_RUNNABLE);
    573   }
    574 
    575   public void testGetScheduledExitingExcutorService_shutdownHookRegistered()
    576       throws InterruptedException {
    577     TestApplication application = new TestApplication();
    578     ScheduledThreadPoolExecutor executor = mock(ScheduledThreadPoolExecutor.class);
    579     ThreadFactory threadFactory = mock(ThreadFactory.class);
    580     when(executor.getThreadFactory()).thenReturn(threadFactory);
    581     application.getExitingScheduledExecutorService(executor);
    582     application.shutdown();
    583     verify(executor).shutdown();
    584   }
    585 
    586   public void testPlatformThreadFactory_default() {
    587     ThreadFactory factory = MoreExecutors.platformThreadFactory();
    588     assertNotNull(factory);
    589     // Executors#defaultThreadFactory() may return a new instance each time.
    590     assertEquals(factory.getClass(), Executors.defaultThreadFactory().getClass());
    591   }
    592 
    593   public void testThreadRenaming() {
    594     Executor renamingExecutor = renamingDecorator(newDirectExecutorService(),
    595         Suppliers.ofInstance("FooBar"));
    596     String oldName = Thread.currentThread().getName();
    597     renamingExecutor.execute(new Runnable() {
    598       @Override public void run() {
    599         assertEquals("FooBar", Thread.currentThread().getName());
    600       }});
    601     assertEquals(oldName, Thread.currentThread().getName());
    602   }
    603 
    604   public void testExecutors_nullCheck() throws Exception {
    605     new ClassSanityTester()
    606         .setDefault(RateLimiter.class, RateLimiter.create(1.0))
    607         .forAllPublicStaticMethods(MoreExecutors.class)
    608         .thatReturn(Executor.class)
    609         .testNulls();
    610   }
    611 
    612   private static class TestApplication extends Application {
    613     private final List<Thread> hooks = Lists.newArrayList();
    614 
    615     @Override synchronized void addShutdownHook(Thread hook) {
    616       hooks.add(hook);
    617     }
    618 
    619     synchronized void shutdown() throws InterruptedException {
    620       for (Thread hook : hooks) {
    621         hook.start();
    622       }
    623       for (Thread hook : hooks) {
    624         hook.join();
    625       }
    626     }
    627   }
    628 
    629   /* Half of a 1-second timeout in nanoseconds */
    630   private static final long HALF_SECOND_NANOS = NANOSECONDS.convert(1L, SECONDS) / 2;
    631 
    632   public void testShutdownAndAwaitTermination_immediateShutdown() throws Exception {
    633     ExecutorService service = Executors.newSingleThreadExecutor();
    634     assertTrue(shutdownAndAwaitTermination(service, 1L, SECONDS));
    635     assertTrue(service.isTerminated());
    636   }
    637 
    638   public void testShutdownAndAwaitTermination_immediateShutdownInternal() throws Exception {
    639     ExecutorService service = mock(ExecutorService.class);
    640     when(service.awaitTermination(HALF_SECOND_NANOS, NANOSECONDS)).thenReturn(true);
    641     when(service.isTerminated()).thenReturn(true);
    642     assertTrue(shutdownAndAwaitTermination(service, 1L, SECONDS));
    643     verify(service).shutdown();
    644     verify(service).awaitTermination(HALF_SECOND_NANOS, NANOSECONDS);
    645   }
    646 
    647   public void testShutdownAndAwaitTermination_forcedShutDownInternal() throws Exception {
    648     ExecutorService service = mock(ExecutorService.class);
    649     when(service.awaitTermination(HALF_SECOND_NANOS, NANOSECONDS))
    650         .thenReturn(false).thenReturn(true);
    651     when(service.isTerminated()).thenReturn(true);
    652     assertTrue(shutdownAndAwaitTermination(service, 1L, SECONDS));
    653     verify(service).shutdown();
    654     verify(service, times(2)).awaitTermination(HALF_SECOND_NANOS, NANOSECONDS);
    655     verify(service).shutdownNow();
    656   }
    657 
    658   public void testShutdownAndAwaitTermination_nonTerminationInternal() throws Exception {
    659     ExecutorService service = mock(ExecutorService.class);
    660     when(service.awaitTermination(HALF_SECOND_NANOS, NANOSECONDS))
    661         .thenReturn(false).thenReturn(false);
    662     assertFalse(shutdownAndAwaitTermination(service, 1L, SECONDS));
    663     verify(service).shutdown();
    664     verify(service, times(2)).awaitTermination(HALF_SECOND_NANOS, NANOSECONDS);
    665     verify(service).shutdownNow();
    666   }
    667 
    668   public void testShutdownAndAwaitTermination_interruptedInternal() throws Exception {
    669     final ExecutorService service = mock(ExecutorService.class);
    670     when(service.awaitTermination(HALF_SECOND_NANOS, NANOSECONDS))
    671         .thenThrow(new InterruptedException());
    672 
    673     final AtomicBoolean terminated = new AtomicBoolean();
    674     // we need to keep this in a flag because t.isInterrupted() returns false after t.join()
    675     final AtomicBoolean interrupted = new AtomicBoolean();
    676     // we need to use another thread because it will be interrupted and thus using
    677     // the current one, owned by JUnit, would make the test fail
    678     Thread thread = new Thread(new Runnable() {
    679       @Override
    680       public void run() {
    681         terminated.set(shutdownAndAwaitTermination(service, 1L, SECONDS));
    682         interrupted.set(Thread.currentThread().isInterrupted());
    683       }
    684     });
    685     thread.start();
    686     thread.join();
    687     verify(service).shutdown();
    688     verify(service).awaitTermination(HALF_SECOND_NANOS, NANOSECONDS);
    689     verify(service).shutdownNow();
    690     assertTrue(interrupted.get());
    691     assertFalse(terminated.get());
    692   }
    693 }
    694