Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2012 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 package com.google.common.util.concurrent.testing;
     18 
     19 import com.google.common.annotations.Beta;
     20 import com.google.common.collect.ImmutableList;
     21 import com.google.common.primitives.Longs;
     22 import com.google.common.util.concurrent.AbstractFuture;
     23 import com.google.common.util.concurrent.AbstractListeningExecutorService;
     24 import com.google.common.util.concurrent.ListenableScheduledFuture;
     25 import com.google.common.util.concurrent.ListeningScheduledExecutorService;
     26 import com.google.common.util.concurrent.MoreExecutors;
     27 
     28 import java.util.List;
     29 import java.util.concurrent.Callable;
     30 import java.util.concurrent.Delayed;
     31 import java.util.concurrent.ScheduledFuture;
     32 import java.util.concurrent.TimeUnit;
     33 
     34 /**
     35  * Factory methods for {@link ExecutorService} for testing.
     36  *
     37  * @author Chris Nokleberg
     38  * @since 14.0
     39  */
     40 @Beta
     41 public final class TestingExecutors {
     42   private TestingExecutors() {}
     43 
     44   /**
     45    * Returns a {@link ScheduledExecutorService} that never executes anything.
     46    *
     47    * <p>The {@code shutdownNow} method of the returned executor always returns an empty list despite
     48    * the fact that everything is still technically awaiting execution.
     49    * The {@code getDelay} method of any {@link ScheduledFuture} returned by the executor will always
     50    * return the max long value instead of the time until the user-specified delay.
     51    */
     52   public static ListeningScheduledExecutorService noOpScheduledExecutor() {
     53     return new NoOpScheduledExecutorService();
     54   }
     55 
     56   /**
     57    * Creates a scheduled executor service that runs each task in the thread
     58    * that invokes {@code execute/submit/schedule}, as in
     59    * {@link CallerRunsPolicy}. This applies both to individually submitted
     60    * tasks and to collections of tasks submitted via {@code invokeAll},
     61    * {@code invokeAny}, {@code schedule}, {@code scheduleAtFixedRate}, and
     62    * {@code scheduleWithFixedDelay}.  In the case of tasks submitted by
     63    * {@code invokeAll} or {@code invokeAny}, tasks will run serially on the
     64    * calling thread.  Tasks are run to completion before a {@code Future} is
     65    * returned to the caller (unless the executor has been shutdown).
     66    *
     67    * <p>The returned executor is backed by the executor returned by
     68    * {@link MoreExecutors#newDirectExecutorService} and subject to the same
     69    * constraints.
     70    *
     71    * <p>Although all tasks are immediately executed in the thread that
     72    * submitted the task, this {@code ExecutorService} imposes a small
     73    * locking overhead on each task submission in order to implement shutdown
     74    * and termination behavior.
     75    *
     76    * <p>Because of the nature of single-thread execution, the methods
     77    * {@code scheduleAtFixedRate} and {@code scheduleWithFixedDelay} are not
     78    * supported by this class and will throw an UnsupportedOperationException.
     79    *
     80    * <p>The implementation deviates from the {@code ExecutorService}
     81    * specification with regards to the {@code shutdownNow} method.  First,
     82    * "best-effort" with regards to canceling running tasks is implemented
     83    * as "no-effort".  No interrupts or other attempts are made to stop
     84    * threads executing tasks.  Second, the returned list will always be empty,
     85    * as any submitted task is considered to have started execution.
     86    * This applies also to tasks given to {@code invokeAll} or {@code invokeAny}
     87    * which are pending serial execution, even the subset of the tasks that
     88    * have not yet started execution.  It is unclear from the
     89    * {@code ExecutorService} specification if these should be included, and
     90    * it's much easier to implement the interpretation that they not be.
     91    * Finally, a call to {@code shutdown} or {@code shutdownNow} may result
     92    * in concurrent calls to {@code invokeAll/invokeAny} throwing
     93    * RejectedExecutionException, although a subset of the tasks may already
     94    * have been executed.
     95    *
     96    * @since 15.0
     97    */
     98   public static SameThreadScheduledExecutorService sameThreadScheduledExecutor() {
     99     return new SameThreadScheduledExecutorService();
    100   }
    101 
    102   private static final class NoOpScheduledExecutorService
    103       extends AbstractListeningExecutorService implements ListeningScheduledExecutorService {
    104 
    105     private volatile boolean shutdown;
    106 
    107     @Override public void shutdown() {
    108       shutdown = true;
    109     }
    110 
    111     @Override public List<Runnable> shutdownNow() {
    112       shutdown();
    113       return ImmutableList.of();
    114     }
    115 
    116     @Override public boolean isShutdown() {
    117       return shutdown;
    118     }
    119 
    120     @Override public boolean isTerminated() {
    121       return shutdown;
    122     }
    123 
    124     @Override public boolean awaitTermination(long timeout, TimeUnit unit) {
    125       return true;
    126     }
    127 
    128     @Override public void execute(Runnable runnable) {}
    129 
    130     @Override public <V> ListenableScheduledFuture<V> schedule(
    131         Callable<V> callable, long delay, TimeUnit unit) {
    132       return NeverScheduledFuture.create();
    133     }
    134 
    135     @Override public ListenableScheduledFuture<?> schedule(
    136         Runnable command, long delay, TimeUnit unit) {
    137       return NeverScheduledFuture.create();
    138     }
    139 
    140     @Override public ListenableScheduledFuture<?> scheduleAtFixedRate(
    141         Runnable command, long initialDelay, long period, TimeUnit unit) {
    142       return NeverScheduledFuture.create();
    143     }
    144 
    145     @Override public ListenableScheduledFuture<?> scheduleWithFixedDelay(
    146         Runnable command, long initialDelay, long delay, TimeUnit unit) {
    147       return NeverScheduledFuture.create();
    148     }
    149 
    150     private static class NeverScheduledFuture<V>
    151         extends AbstractFuture<V> implements ListenableScheduledFuture<V> {
    152 
    153       static <V> NeverScheduledFuture<V> create() {
    154         return new NeverScheduledFuture<V>();
    155       }
    156 
    157       @Override public long getDelay(TimeUnit unit) {
    158         return Long.MAX_VALUE;
    159       }
    160 
    161       @Override public int compareTo(Delayed other) {
    162         return Longs.compare(getDelay(TimeUnit.NANOSECONDS), other.getDelay(TimeUnit.NANOSECONDS));
    163       }
    164     }
    165   }
    166 }
    167