BoltsTest/src/bolts/TaskTest.java (431 lines of code) (raw):
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
package bolts;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import bolts.AggregateException;
import bolts.Continuation;
import bolts.Task;
import junit.framework.TestCase;
public class TaskTest extends TestCase {
private void runTaskTest(Callable<Task<?>> callable) {
try {
Task<?> task = callable.call();
task.waitForCompletion();
if (task.isFaulted()) {
Exception error = task.getError();
if (error instanceof RuntimeException) {
throw (RuntimeException) error;
}
throw new RuntimeException(error);
} else if (task.isCancelled()) {
throw new RuntimeException(new CancellationException());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void testPrimitives() {
Task<Integer> complete = Task.forResult(5);
Task<Integer> error = Task.forError(new RuntimeException());
Task<Integer> cancelled = Task.cancelled();
assertTrue(complete.isCompleted());
assertEquals(5, complete.getResult().intValue());
assertFalse(complete.isFaulted());
assertFalse(complete.isCancelled());
assertTrue(error.isCompleted());
assertTrue(error.getError() instanceof RuntimeException);
assertTrue(error.isFaulted());
assertFalse(error.isCancelled());
assertTrue(cancelled.isCompleted());
assertFalse(cancelled.isFaulted());
assertTrue(cancelled.isCancelled());
}
public void testSynchronousContinuation() {
final Task<Integer> complete = Task.forResult(5);
final Task<Integer> error = Task.forError(new RuntimeException());
final Task<Integer> cancelled = Task.cancelled();
complete.continueWith(new Continuation<Integer, Void>() {
public Void then(Task<Integer> task) {
assertEquals(complete, task);
assertTrue(task.isCompleted());
assertEquals(5, task.getResult().intValue());
assertFalse(task.isFaulted());
assertFalse(task.isCancelled());
return null;
}
});
error.continueWith(new Continuation<Integer, Void>() {
public Void then(Task<Integer> task) {
assertEquals(error, task);
assertTrue(task.isCompleted());
assertTrue(task.getError() instanceof RuntimeException);
assertTrue(task.isFaulted());
assertFalse(task.isCancelled());
return null;
}
});
cancelled.continueWith(new Continuation<Integer, Void>() {
public Void then(Task<Integer> task) {
assertEquals(cancelled, task);
assertTrue(cancelled.isCompleted());
assertFalse(cancelled.isFaulted());
assertTrue(cancelled.isCancelled());
return null;
}
});
}
public void testSynchronousChaining() {
Task<Integer> first = Task.forResult(1);
Task<Integer> second = first.continueWith(new Continuation<Integer, Integer>() {
public Integer then(Task<Integer> task) {
return 2;
}
});
Task<Integer> third = second.continueWithTask(new Continuation<Integer, Task<Integer>>() {
public Task<Integer> then(Task<Integer> task) {
return Task.forResult(3);
}
});
assertTrue(first.isCompleted());
assertTrue(second.isCompleted());
assertTrue(third.isCompleted());
assertEquals(1, first.getResult().intValue());
assertEquals(2, second.getResult().intValue());
assertEquals(3, third.getResult().intValue());
}
public void testBackgroundCall() {
runTaskTest(new Callable<Task<?>>() {
public Task<?> call() throws Exception {
return Task.callInBackground(new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(100);
return 5;
}
}).continueWith(new Continuation<Integer, Void>() {
public Void then(Task<Integer> task) {
assertEquals(5, task.getResult().intValue());
return null;
}
});
}
});
}
public void testBackgroundCallWaiting() throws Exception {
Task<Integer> task = Task.callInBackground(new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(100);
return 5;
}
});
task.waitForCompletion();
assertTrue(task.isCompleted());
assertEquals(5, task.getResult().intValue());
}
public void testBackgroundCallWaitingOnError() throws Exception {
Task<Integer> task = Task.callInBackground(new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(100);
throw new RuntimeException();
}
});
task.waitForCompletion();
assertTrue(task.isCompleted());
assertTrue(task.isFaulted());
}
public void testBackgroundCallWaitOnCancellation() throws Exception {
Task<Integer> task = Task.callInBackground(new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(100);
return 5;
}
}).continueWithTask(new Continuation<Integer, Task<Integer>>() {
public Task<Integer> then(Task<Integer> task) {
return Task.cancelled();
}
});
task.waitForCompletion();
assertTrue(task.isCompleted());
assertTrue(task.isCancelled());
}
public void testBackgroundError() {
runTaskTest(new Callable<Task<?>>() {
public Task<?> call() throws Exception {
return Task.callInBackground(new Callable<Integer>() {
public Integer call() throws Exception {
throw new IllegalStateException();
}
}).continueWith(new Continuation<Integer, Void>() {
public Void then(Task<Integer> task) {
assertTrue(task.isFaulted());
assertTrue(task.getError() instanceof IllegalStateException);
return null;
}
});
}
});
}
public void testWhenAllSuccess() {
runTaskTest(new Callable<Task<?>>() {
@Override
public Task<?> call() throws Exception {
final ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (int i = 0; i < 20; i++) {
Task<Void> task = Task.callInBackground(new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep((long) (Math.random() * 1000));
return null;
}
});
tasks.add(task);
}
return Task.whenAll(tasks).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) {
assertTrue(task.isCompleted());
assertFalse(task.isFaulted());
assertFalse(task.isCancelled());
for (Task<Void> t : tasks) {
assertTrue(t.isCompleted());
}
return null;
}
});
}
});
}
public void testWhenAllOneError() {
final Exception error = new RuntimeException("This task failed.");
runTaskTest(new Callable<Task<?>>() {
@Override
public Task<?> call() throws Exception {
final ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (int i = 0; i < 20; i++) {
final int number = i;
Task<Void> task = Task.callInBackground(new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep((long) (Math.random() * 1000));
if (number == 10) {
throw error;
}
return null;
}
});
tasks.add(task);
}
return Task.whenAll(tasks).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) {
assertTrue(task.isCompleted());
assertTrue(task.isFaulted());
assertFalse(task.isCancelled());
assertFalse(task.getError() instanceof AggregateException);
assertEquals(error, task.getError());
for (Task<Void> t : tasks) {
assertTrue(t.isCompleted());
}
return null;
}
});
}
});
}
public void testWhenAllTwoErrors() {
final Exception error = new RuntimeException("This task failed.");
runTaskTest(new Callable<Task<?>>() {
@Override
public Task<?> call() throws Exception {
final ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (int i = 0; i < 20; i++) {
final int number = i;
Task<Void> task = Task.callInBackground(new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep((long) (Math.random() * 1000));
if (number == 10 || number == 11) {
throw error;
}
return null;
}
});
tasks.add(task);
}
return Task.whenAll(tasks).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) {
assertTrue(task.isCompleted());
assertTrue(task.isFaulted());
assertFalse(task.isCancelled());
assertTrue(task.getError() instanceof AggregateException);
assertEquals(2, ((AggregateException)task.getError()).getErrors().size());
assertEquals(error, ((AggregateException)task.getError()).getErrors().get(0));
assertEquals(error, ((AggregateException)task.getError()).getErrors().get(1));
for (Task<Void> t : tasks) {
assertTrue(t.isCompleted());
}
return null;
}
});
}
});
}
public void testWhenAllCancel() {
runTaskTest(new Callable<Task<?>>() {
@Override
public Task<?> call() throws Exception {
final ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (int i = 0; i < 20; i++) {
final Task<Void>.TaskCompletionSource tcs = Task.create();
final int number = i;
Task.callInBackground(new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep((long) (Math.random() * 1000));
if (number == 10) {
tcs.setCancelled();
} else {
tcs.setResult(null);
}
return null;
}
});
tasks.add(tcs.getTask());
}
return Task.whenAll(tasks).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) {
assertTrue(task.isCompleted());
assertFalse(task.isFaulted());
assertTrue(task.isCancelled());
for (Task<Void> t : tasks) {
assertTrue(t.isCompleted());
}
return null;
}
});
}
});
}
public void testAsyncChaining() {
runTaskTest(new Callable<Task<?>>() {
public Task<?> call() throws Exception {
final ArrayList<Integer> sequence = new ArrayList<Integer>();
Task<Void> result = Task.forResult(null);
for (int i = 0; i < 20; i++) {
final int taskNumber = i;
result = result.continueWithTask(new Continuation<Void, Task<Void>>() {
public Task<Void> then(Task<Void> task) {
return Task.callInBackground(new Callable<Void>() {
public Void call() throws Exception {
sequence.add(taskNumber);
return null;
}
});
}
});
}
result = result.continueWith(new Continuation<Void, Void>() {
public Void then(Task<Void> task) {
assertEquals(20, sequence.size());
for (int i = 0; i < 20; i++) {
assertEquals(i, sequence.get(i).intValue());
}
return null;
}
});
return result;
}
});
}
public void testOnSuccess() {
Continuation<Integer, Integer> continuation = new Continuation<Integer, Integer>() {
public Integer then(Task<Integer> task) {
return task.getResult().intValue() + 1;
}
};
Task<Integer> complete = Task.forResult(5).onSuccess(continuation);
Task<Integer> error = Task.<Integer> forError(new IllegalStateException()).onSuccess(
continuation);
Task<Integer> cancelled = Task.<Integer> cancelled().onSuccess(continuation);
assertTrue(complete.isCompleted());
assertEquals(6, complete.getResult().intValue());
assertFalse(complete.isFaulted());
assertFalse(complete.isCancelled());
assertTrue(error.isCompleted());
assertTrue(error.getError() instanceof RuntimeException);
assertTrue(error.isFaulted());
assertFalse(error.isCancelled());
assertTrue(cancelled.isCompleted());
assertFalse(cancelled.isFaulted());
assertTrue(cancelled.isCancelled());
}
public void testOnSuccessTask() {
Continuation<Integer, Task<Integer>> continuation = new Continuation<Integer, Task<Integer>>() {
public Task<Integer> then(Task<Integer> task) {
return Task.forResult(task.getResult().intValue() + 1);
}
};
Task<Integer> complete = Task.forResult(5).onSuccessTask(continuation);
Task<Integer> error = Task.<Integer> forError(new IllegalStateException()).onSuccessTask(
continuation);
Task<Integer> cancelled = Task.<Integer> cancelled().onSuccessTask(continuation);
assertTrue(complete.isCompleted());
assertEquals(6, complete.getResult().intValue());
assertFalse(complete.isFaulted());
assertFalse(complete.isCancelled());
assertTrue(error.isCompleted());
assertTrue(error.getError() instanceof RuntimeException);
assertTrue(error.isFaulted());
assertFalse(error.isCancelled());
assertTrue(cancelled.isCompleted());
assertFalse(cancelled.isFaulted());
assertTrue(cancelled.isCancelled());
}
public void testContinueWhile() {
final AtomicInteger count = new AtomicInteger(0);
runTaskTest(new Callable<Task<?>>() {
public Task<?> call() throws Exception {
return Task.forResult(null).continueWhile(new Callable<Boolean>() {
public Boolean call() throws Exception {
return count.get() < 10;
}
}, new Continuation<Void, Task<Void>>() {
public Task<Void> then(Task<Void> task) throws Exception {
count.incrementAndGet();
return null;
}
}).continueWith(new Continuation<Void, Void>() {
public Void then(Task<Void> task) throws Exception {
assertEquals(10, count.get());
return null;
}
});
}
});
}
public void testContinueWhileAsync() {
final AtomicInteger count = new AtomicInteger(0);
runTaskTest(new Callable<Task<?>>() {
public Task<?> call() throws Exception {
return Task.forResult(null).continueWhile(new Callable<Boolean>() {
public Boolean call() throws Exception {
return count.get() < 10;
}
}, new Continuation<Void, Task<Void>>() {
public Task<Void> then(Task<Void> task) throws Exception {
count.incrementAndGet();
return null;
}
}, Executors.newCachedThreadPool()).continueWith(new Continuation<Void, Void>() {
public Void then(Task<Void> task) throws Exception {
assertEquals(10, count.get());
return null;
}
});
}
});
}
}