1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
20 import static com.google.common.util.concurrent.Runnables.doNothing;
21 
22 import com.google.common.base.Predicate;
23 import com.google.common.base.Predicates;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.Iterables;
26 import com.google.common.collect.Lists;
27 
28 import junit.framework.TestCase;
29 
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.concurrent.Callable;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.ExecutorService;
35 import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.TimeoutException;
38 
39 /**
40  * Test for {@link WrappingExecutorService}
41  *
42  * @author Chris Nokleberg
43  */
44 public class WrappingExecutorServiceTest extends TestCase {
45   private static final String RESULT_VALUE = "ran";
46   // Uninteresting delegations
testDelegations()47   public void testDelegations() throws InterruptedException {
48     MockExecutor mock = new MockExecutor();
49     TestExecutor testExecutor = new TestExecutor(mock);
50     assertFalse(testExecutor.awaitTermination(10, TimeUnit.MILLISECONDS));
51     mock.assertLastMethodCalled("awaitTermination");
52     assertFalse(testExecutor.isTerminated());
53     mock.assertLastMethodCalled("isTerminated");
54     assertFalse(testExecutor.isShutdown());
55     mock.assertLastMethodCalled("isShutdown");
56     testExecutor.shutdown();
57     mock.assertLastMethodCalled("shutdown");
58     List<Runnable> list = testExecutor.shutdownNow();
59     mock.assertLastMethodCalled("shutdownNow");
60     assertEquals(ImmutableList.of(), list);
61   }
62 
testExecute()63   public void testExecute() {
64     MockExecutor mock = new MockExecutor();
65     TestExecutor testExecutor = new TestExecutor(mock);
66     testExecutor.execute(doNothing());
67     mock.assertLastMethodCalled("execute");
68   }
69 
testSubmit()70   public void testSubmit() throws InterruptedException, ExecutionException {
71     {
72       MockExecutor mock = new MockExecutor();
73       TestExecutor testExecutor = new TestExecutor(mock);
74       Future<?> f = testExecutor.submit(doNothing());
75       mock.assertLastMethodCalled("submit");
76       f.get();
77     }
78     {
79       MockExecutor mock = new MockExecutor();
80       TestExecutor testExecutor = new TestExecutor(mock);
81       Future<String> f = testExecutor.submit(doNothing(), RESULT_VALUE);
82       mock.assertLastMethodCalled("submit");
83       assertEquals(RESULT_VALUE, f.get());
84     }
85     {
86       MockExecutor mock = new MockExecutor();
87       TestExecutor testExecutor = new TestExecutor(mock);
88       Callable<String> task = Callables.returning(RESULT_VALUE);
89       Future<String> f = testExecutor.submit(task);
90       mock.assertLastMethodCalled("submit");
91       assertEquals(RESULT_VALUE, f.get());
92     }
93   }
94 
testInvokeAll()95   public void testInvokeAll() throws InterruptedException, ExecutionException {
96     List<Callable<String>> tasks = createTasks(3);
97     {
98       MockExecutor mock = new MockExecutor();
99       TestExecutor testExecutor = new TestExecutor(mock);
100       List<Future<String>> futures = testExecutor.invokeAll(tasks);
101       mock.assertLastMethodCalled("invokeAll");
102       checkResults(futures);
103     }
104     {
105       MockExecutor mock = new MockExecutor();
106       TimeUnit unit = TimeUnit.SECONDS;
107       long timeout = 5;
108       TestExecutor testExecutor = new TestExecutor(mock);
109       List<Future<String>> futures = testExecutor.invokeAll(tasks, timeout, unit);
110       mock.assertMethodWithTimeout("invokeAll", timeout, unit);
111       checkResults(futures);
112     }
113   }
114 
testInvokeAny()115   public void testInvokeAny() throws InterruptedException, ExecutionException, TimeoutException {
116     List<Callable<String>> tasks = createTasks(3);
117     {
118       MockExecutor mock = new MockExecutor();
119       TestExecutor testExecutor = new TestExecutor(mock);
120       String s = testExecutor.invokeAny(tasks);
121       assertEquals("ran0", s);
122       mock.assertLastMethodCalled("invokeAny");
123     }
124     {
125       MockExecutor mock = new MockExecutor();
126       TimeUnit unit = TimeUnit.SECONDS;
127       long timeout = 5;
128       TestExecutor testExecutor = new TestExecutor(mock);
129       String s = testExecutor.invokeAny(tasks, timeout, unit);
130       assertEquals(RESULT_VALUE + "0", s);
131       mock.assertMethodWithTimeout("invokeAny", timeout, unit);
132     }
133   }
134 
checkResults(List<Future<String>> futures)135   private static void checkResults(List<Future<String>> futures)
136       throws InterruptedException, ExecutionException {
137     for (int i = 0; i < futures.size(); i++) {
138       assertEquals(RESULT_VALUE + i, futures.get(i).get());
139     }
140   }
141 
createTasks(int n)142   private static List<Callable<String>> createTasks(int n) {
143     List<Callable<String>> callables = Lists.newArrayList();
144     for (int i = 0; i < n; i++) {
145       callables.add(Callables.returning(RESULT_VALUE + i));
146     }
147     return callables;
148   }
149 
150   private static final class WrappedCallable<T> implements Callable<T> {
151     private final Callable<T> delegate;
152 
WrappedCallable(Callable<T> delegate)153     public WrappedCallable(Callable<T> delegate) {
154       this.delegate = delegate;
155     }
156 
157     @Override
call()158     public T call() throws Exception {
159       return delegate.call();
160     }
161   }
162 
163   private static final class WrappedRunnable implements Runnable {
164     private final Runnable delegate;
165 
WrappedRunnable(Runnable delegate)166     public WrappedRunnable(Runnable delegate) {
167       this.delegate = delegate;
168     }
169 
170     @Override
run()171     public void run() {
172       delegate.run();
173     }
174   }
175 
176   private static final class TestExecutor extends WrappingExecutorService {
TestExecutor(MockExecutor mock)177     public TestExecutor(MockExecutor mock) {
178       super(mock);
179     }
180 
181     @Override
wrapTask(Callable<T> callable)182     protected <T> Callable<T> wrapTask(Callable<T> callable) {
183       return new WrappedCallable<T>(callable);
184     }
185 
wrapTask(Runnable command)186     @Override protected Runnable wrapTask(Runnable command) {
187       return new WrappedRunnable(command);
188     }
189   }
190 
191   // TODO: If this test can ever depend on EasyMock or the like, use it instead.
192   private static final class MockExecutor implements ExecutorService {
193     private String lastMethodCalled = "";
194     private long lastTimeoutInMillis = -1;
195     private ExecutorService inline = newDirectExecutorService();
196 
assertLastMethodCalled(String method)197     public void assertLastMethodCalled(String method) {
198       assertEquals(method, lastMethodCalled);
199     }
200 
assertMethodWithTimeout(String method, long timeout, TimeUnit unit)201     public void assertMethodWithTimeout(String method, long timeout, TimeUnit unit) {
202       assertLastMethodCalled(method + "Timeout");
203       assertEquals(unit.toMillis(timeout), lastTimeoutInMillis);
204     }
205 
206     @Override
awaitTermination(long timeout, TimeUnit unit)207     public boolean awaitTermination(long timeout, TimeUnit unit) {
208       lastMethodCalled = "awaitTermination";
209       return false;
210     }
211 
212     @Override
invokeAll(Collection<? extends Callable<T>> tasks)213     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
214         throws InterruptedException {
215       lastMethodCalled = "invokeAll";
216       assertTaskWrapped(tasks);
217       return inline.invokeAll(tasks);
218     }
219 
220     @Override
invokeAll( Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)221     public <T> List<Future<T>> invokeAll(
222         Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
223         throws InterruptedException {
224       assertTaskWrapped(tasks);
225       lastMethodCalled = "invokeAllTimeout";
226       lastTimeoutInMillis = unit.toMillis(timeout);
227       return inline.invokeAll(tasks, timeout, unit);
228     }
229 
230     // Define the invokeAny methods to invoke the first task
231     @Override
invokeAny(Collection<? extends Callable<T>> tasks)232     public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
233         throws ExecutionException, InterruptedException {
234       assertTaskWrapped(tasks);
235       lastMethodCalled = "invokeAny";
236       return inline.submit(Iterables.get(tasks, 0)).get();
237     }
238 
239     @Override
invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)240     public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
241         throws ExecutionException, InterruptedException, TimeoutException {
242       assertTaskWrapped(tasks);
243       lastMethodCalled = "invokeAnyTimeout";
244       lastTimeoutInMillis = unit.toMillis(timeout);
245       return inline.submit(Iterables.get(tasks, 0)).get(timeout, unit);
246     }
247 
248     @Override
isShutdown()249     public boolean isShutdown() {
250       lastMethodCalled = "isShutdown";
251       return false;
252     }
253 
254     @Override
isTerminated()255     public boolean isTerminated() {
256       lastMethodCalled = "isTerminated";
257       return false;
258     }
259 
260     @Override
shutdown()261     public void shutdown() {
262       lastMethodCalled = "shutdown";
263     }
264 
265     @Override
shutdownNow()266     public List<Runnable> shutdownNow() {
267       lastMethodCalled = "shutdownNow";
268       return ImmutableList.of();
269     }
270 
271     @Override
submit(Callable<T> task)272     public <T> Future<T> submit(Callable<T> task) {
273       lastMethodCalled = "submit";
274       assertTrue(task instanceof WrappedCallable);
275       return inline.submit(task);
276     }
277 
278     @Override
submit(Runnable task)279     public Future<?> submit(Runnable task) {
280       lastMethodCalled = "submit";
281       assertTrue(task instanceof WrappedRunnable);
282       return inline.submit(task);
283     }
284 
285     @Override
submit(Runnable task, T result)286     public <T> Future<T> submit(Runnable task, T result) {
287       lastMethodCalled = "submit";
288       assertTrue(task instanceof WrappedRunnable);
289       return inline.submit(task, result);
290     }
291 
292     @Override
execute(Runnable command)293     public void execute(Runnable command) {
294       lastMethodCalled = "execute";
295       assertTrue(command instanceof WrappedRunnable);
296       inline.execute(command);
297     }
298 
assertTaskWrapped( Collection<? extends Callable<T>> tasks)299     private static <T> void assertTaskWrapped(
300         Collection<? extends Callable<T>> tasks) {
301       Predicate<Object> p = Predicates.instanceOf(WrappedCallable.class);
302       assertTrue(Iterables.all(tasks, p));
303     }
304 
305   }
306 }
307