1/*
2 * Copyright (C) 2009 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
17package com.google.common.util.concurrent;
18
19import junit.framework.TestCase;
20
21import java.util.concurrent.Callable;
22import java.util.concurrent.CountDownLatch;
23import java.util.concurrent.ExecutionException;
24import java.util.concurrent.ExecutorService;
25import java.util.concurrent.Executors;
26import java.util.concurrent.TimeUnit;
27
28/**
29 * Test case for {@link ListenableFutureTask}.
30 *
31 * @author Sven Mawson
32 */
33public class ListenableFutureTaskTest extends TestCase {
34
35  private ExecutorService exec;
36
37  protected final CountDownLatch runLatch = new CountDownLatch(1);
38  protected final CountDownLatch taskLatch = new CountDownLatch(1);
39  protected final CountDownLatch listenerLatch = new CountDownLatch(1);
40
41  protected volatile boolean throwException = false;
42
43  protected final ListenableFutureTask<Integer> task =
44      ListenableFutureTask.create(new Callable<Integer>() {
45    @Override
46    public Integer call() throws Exception {
47      runLatch.countDown();
48      taskLatch.await();
49      if (throwException) {
50        throw new IllegalStateException("Fail");
51      }
52      return 25;
53    }
54  });
55
56  @Override
57  protected void setUp() throws Exception {
58    super.setUp();
59
60    exec = Executors.newCachedThreadPool();
61
62    task.addListener(new Runnable() {
63      @Override
64      public void run() {
65        listenerLatch.countDown();
66      }
67    }, MoreExecutors.sameThreadExecutor());
68  }
69
70  @Override
71  protected void tearDown() throws Exception {
72    if (exec != null) {
73      exec.shutdown();
74    }
75
76    super.tearDown();
77  }
78
79  public void testListenerDoesNotRunUntilTaskCompletes() throws Exception {
80
81    // Test default state of not started.
82    assertEquals(1, listenerLatch.getCount());
83    assertFalse(task.isDone());
84    assertFalse(task.isCancelled());
85
86    // Start the task to put it in the RUNNING state.  Have to use a separate
87    // thread because the task will block on the task latch after unblocking
88    // the run latch.
89    exec.execute(task);
90    runLatch.await();
91    assertEquals(1, listenerLatch.getCount());
92    assertFalse(task.isDone());
93    assertFalse(task.isCancelled());
94
95    // Finish the task by unblocking the task latch.  Then wait for the
96    // listener to be called by blocking on the listener latch.
97    taskLatch.countDown();
98    assertEquals(25, task.get().intValue());
99    assertTrue(listenerLatch.await(5, TimeUnit.SECONDS));
100    assertTrue(task.isDone());
101    assertFalse(task.isCancelled());
102  }
103
104  public void testListenerCalledOnException() throws Exception {
105    throwException = true;
106
107    // Start up the task and unblock the latch to finish the task.
108    exec.execute(task);
109    runLatch.await();
110    taskLatch.countDown();
111
112    try {
113      task.get(5, TimeUnit.SECONDS);
114      fail("Should have propagated the failure.");
115    } catch (ExecutionException e) {
116      assertEquals(IllegalStateException.class, e.getCause().getClass());
117    }
118
119    assertTrue(listenerLatch.await(5, TimeUnit.SECONDS));
120    assertTrue(task.isDone());
121    assertFalse(task.isCancelled());
122  }
123
124  public void testListenerCalledOnCancelFromNotRunning() throws Exception {
125    task.cancel(false);
126    assertTrue(task.isDone());
127    assertTrue(task.isCancelled());
128    assertEquals(1, runLatch.getCount());
129
130    // Wait for the listeners to be called, don't rely on the same-thread exec.
131    listenerLatch.await(5, TimeUnit.SECONDS);
132    assertTrue(task.isDone());
133    assertTrue(task.isCancelled());
134
135    // Make sure we didn't run anything.
136    assertEquals(1, runLatch.getCount());
137  }
138
139  public void testListenerCalledOnCancelFromRunning() throws Exception {
140    exec.execute(task);
141    runLatch.await();
142
143    // Task has started up, cancel it while it's running.
144    task.cancel(true);
145    assertTrue(task.isDone());
146    assertTrue(task.isCancelled());
147    assertEquals(1, taskLatch.getCount());
148
149    // Wait for the listeners to be called.
150    listenerLatch.await(5, TimeUnit.SECONDS);
151    assertTrue(task.isDone());
152    assertTrue(task.isCancelled());
153    assertEquals(1, taskLatch.getCount());
154  }
155}
156