/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.tasks;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.rmi.RemoteException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class TasksTest {
private static final Object RESULT = new Object();
private static final RemoteException EXCEPTION = new RemoteException();
private static final int SCHEDULE_DELAY_MS = 50;
private static final int TIMEOUT_MS = 200;
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
@Rule public ExpectedException expectedException = ExpectedException.none();
@Test
public void testForResult() throws Exception {
Task<Object> task = Tasks.forResult(RESULT);
assertEquals(RESULT, task.getResult());
}
@Test
public void testForResult_nullResult() throws Exception {
Task<Void> task = Tasks.forResult(null);
assertNull(task.getResult());
}
@Test
public void testForException() {
Task<Void> task = Tasks.forException(EXCEPTION);
assertEquals(EXCEPTION, task.getException());
}
@Test(expected = NullPointerException.class)
@SuppressWarnings("ConstantConditions")
public void testForException_nullException() {
Tasks.forException(null);
}
@Test
public void testCall_nonNullResult() {
Task<Object> task =
Tasks.call(
TaskExecutors.DIRECT,
new Callable<Object>() {
@Override
public Object call() throws Exception {
return RESULT;
}
});
assertEquals(RESULT, task.getResult());
}
@Test
public void testCall_nullResult() {
Task<Void> task =
Tasks.call(
TaskExecutors.DIRECT,
new Callable<Void>() {
@Override
public Void call() throws Exception {
return null;
}
});
assertNull(task.getResult());
}
@Test
public void testCall_exception() {
Task<Void> task =
Tasks.call(
TaskExecutors.DIRECT,
new Callable<Void>() {
@Override
public Void call() throws Exception {
throw EXCEPTION;
}
});
assertEquals(EXCEPTION, task.getException());
}
@Test(expected = NullPointerException.class)
public void testCall_nullCallable() {
Tasks.call(null);
}
@Test(expected = NullPointerException.class)
public void testCall_nullExecutor() {
Tasks.call(
null,
new Callable<Void>() {
@Override
public Void call() throws Exception {
return null;
}
});
}
@Test
public void testAwait() throws Exception {
TaskCompletionSource<Object> completionSource = new TaskCompletionSource<>();
scheduleResult(completionSource);
assertEquals(
RESULT, Tasks.await(completionSource.getTask(), TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
@Test
public void testAwait_noTimeout() throws Exception {
TaskCompletionSource<Object> completionSource = new TaskCompletionSource<>();
scheduleResult(completionSource);
assertEquals(RESULT, Tasks.await(completionSource.getTask()));
}
@Test
public void testAwait_exception() throws Exception {
expectedException.expect(ExecutionException.class);
expectedException.expectCause(Matchers.is(EXCEPTION));
TaskCompletionSource<Void> completionSource = new TaskCompletionSource<>();
scheduleException(completionSource);
Tasks.await(completionSource.getTask(), TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test
public void testAwait_noTimeoutException() throws Exception {
expectedException.expect(ExecutionException.class);
expectedException.expectCause(Matchers.is(EXCEPTION));
TaskCompletionSource<Void> completionSource = new TaskCompletionSource<>();
scheduleException(completionSource);
Tasks.await(completionSource.getTask());
}
@Test
public void testAwait_alreadyFailed() throws Exception {
expectedException.expect(ExecutionException.class);
expectedException.expectCause(Matchers.is(EXCEPTION));
Task<Object> task = Tasks.forException(EXCEPTION);
Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test
public void testAwait_noTimeoutAlreadyFailed() throws Exception {
expectedException.expect(ExecutionException.class);
expectedException.expectCause(Matchers.is(EXCEPTION));
Task<Object> task = Tasks.forException(EXCEPTION);
Tasks.await(task);
}
@Test
public void testAwait_alreadySucceeded() throws Exception {
Task<Object> task = Tasks.forResult(RESULT);
assertEquals(RESULT, Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
@Test
public void testAwait_noTimeoutAlreadySucceeded() throws Exception {
Task<Object> task = Tasks.forResult(RESULT);
assertEquals(RESULT, Tasks.await(task));
}
@Test(expected = InterruptedException.class)
public void testAwait_interrupted() throws Exception {
Task<Void> task = new TaskImpl<>();
scheduleInterrupt();
Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test(expected = InterruptedException.class)
public void testAwait_noTimeoutInterrupted() throws Exception {
Task<Void> task = new TaskImpl<>();
scheduleInterrupt();
Tasks.await(task);
}
@Test(expected = TimeoutException.class)
public void testAwait_timeout() throws Exception {
TaskImpl<Void> task = new TaskImpl<>();
Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test(expected = TimeoutException.class)
public void testWhenAll_notCompleted() throws Exception {
Task<Void> task1 = new TaskImpl<>();
Task<Void> task2 = new TaskImpl<>();
Task<Void> task = Tasks.whenAll(task1, task2);
Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test(expected = TimeoutException.class)
public void testWhenAll_partiallyCompleted() throws Exception {
Task<Object> task1 = Tasks.forResult(RESULT);
Task<Void> task2 = new TaskImpl<>();
Task<Void> task = Tasks.whenAll(task1, task2);
Tasks.await(task, TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
@Test
public void testWhenAll_completedFailure() throws Exception {
expectedException.expect(ExecutionException.class);
expectedException.expectCause(Matchers.any(ExecutionException.class));
Task<Object> task1 = Tasks.forResult(RESULT);
Task<Object> task2 = Tasks.forException(EXCEPTION);
Task<Void> task = Tasks.whenAll(task1, task2);
Tasks.await(task);
}
@Test
public void testWhenAll_completedSuccess() throws Exception {
Task<Object> task1 = Tasks.forResult(RESULT);
Task<Object> task2 = Tasks.forResult(RESULT);
Task<Void> task = Tasks.whenAll(task1, task2);
assertNull(Tasks.await(task));
}
@Test
public void testWhenAll_completedEmpty() throws Exception {
Task<Void> task = Tasks.whenAll();
assertNull(Tasks.await(task));
}
@Test(expected = NullPointerException.class)
public void testWhenAll_nullOnInput() throws Exception {
Task<Object> task = Tasks.forResult(RESULT);
Tasks.whenAll(task, null, task);
}
private void scheduleResult(final TaskCompletionSource<Object> completionSource) {
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
executor.schedule(
new Runnable() {
@Override
public void run() {
completionSource.setResult(RESULT);
}
},
SCHEDULE_DELAY_MS,
TimeUnit.MILLISECONDS);
}
private void scheduleException(final TaskCompletionSource<?> completionSource) {
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
executor.schedule(
new Runnable() {
@Override
public void run() {
completionSource.setException(EXCEPTION);
}
},
SCHEDULE_DELAY_MS,
TimeUnit.MILLISECONDS);
}
private void scheduleInterrupt() {
final Thread testThread = Thread.currentThread();
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
executor.schedule(
new Runnable() {
@Override
public void run() {
testThread.interrupt();
}
},
SCHEDULE_DELAY_MS,
TimeUnit.MILLISECONDS);
}
}