/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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.hazelcast.durableexecutor;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.Member;
import com.hazelcast.executor.ExecutorServiceTestSupport;
import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class DurableSingleNodeTest extends ExecutorServiceTestSupport {
private DurableExecutorService executor;
@Before
public void setUp() {
executor = createSingleNodeDurableExecutorService("test", 1);
}
@Test
public void hazelcastInstanceAware_expectInjection() throws Throwable {
HazelcastInstanceAwareRunnable task = new HazelcastInstanceAwareRunnable();
try {
executor.submit(task).get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
@Test(expected = NullPointerException.class)
@SuppressWarnings("ConstantConditions")
public void submitNullTask_expectFailure() {
executor.submit((Callable<?>) null);
}
@Test
public void submitBasicTask() throws Exception {
Callable<String> task = new BasicTestCallable();
Future future = executor.submit(task);
assertEquals(future.get(), BasicTestCallable.RESULT);
}
@Test
public void executionCallback_notifiedOnSuccess() {
final CountDownLatch latch = new CountDownLatch(1);
Callable<String> task = new BasicTestCallable();
ExecutionCallback<String> executionCallback = new ExecutionCallback<String>() {
public void onResponse(String response) {
latch.countDown();
}
public void onFailure(Throwable t) {
}
};
executor.submit(task).andThen(executionCallback);
assertOpenEventually(latch);
}
@Test
public void executionCallback_notifiedOnFailure() {
final CountDownLatch latch = new CountDownLatch(1);
FailingTestTask task = new FailingTestTask();
ExecutionCallback<String> executionCallback = new ExecutionCallback<String>() {
public void onResponse(String response) {
}
public void onFailure(Throwable t) {
latch.countDown();
}
};
executor.submit(task).andThen(executionCallback);
assertOpenEventually(latch);
}
@Test
public void isDoneAfterGet() throws Exception {
Callable<String> task = new BasicTestCallable();
Future future = executor.submit(task);
assertEquals(future.get(), BasicTestCallable.RESULT);
assertTrue(future.isDone());
}
@Test
public void issue129() throws Exception {
for (int i = 0; i < 1000; i++) {
Callable<String>
task1 = new BasicTestCallable(),
task2 = new BasicTestCallable();
Future<String>
future1 = executor.submit(task1),
future2 = executor.submit(task2);
assertEquals(future2.get(), BasicTestCallable.RESULT);
assertTrue(future2.isDone());
assertEquals(future1.get(), BasicTestCallable.RESULT);
assertTrue(future1.isDone());
}
}
@Test
public void issue292() throws Exception {
final BlockingQueue<Member> responseQueue = new ArrayBlockingQueue<Member>(1);
executor.submit(new MemberCheck()).andThen(new ExecutionCallback<Member>() {
public void onResponse(Member response) {
responseQueue.offer(response);
}
public void onFailure(Throwable t) {
}
});
assertNotNull(responseQueue.poll(10, TimeUnit.SECONDS));
}
@Test(timeout = 10000)
public void taskSubmitsNestedTask() throws Exception {
Callable<String> task = new NestedExecutorTask();
executor.submit(task).get();
}
@Test
public void getManyTimesFromSameFuture() throws Exception {
Callable<String> task = new BasicTestCallable();
Future<String> future = executor.submit(task);
for (int i = 0; i < 4; i++) {
assertEquals(future.get(), BasicTestCallable.RESULT);
assertTrue(future.isDone());
}
}
/**
* Shutdown-related method behaviour when the cluster is running.
*/
@Test
public void shutdownBehaviour() {
// fresh instance, is not shutting down
assertFalse(executor.isShutdown());
assertFalse(executor.isTerminated());
executor.shutdown();
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
// shutdownNow() should return an empty list and be ignored
List<Runnable> pending = executor.shutdownNow();
assertTrue(pending.isEmpty());
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
// awaitTermination() should return immediately false
try {
boolean terminated = executor.awaitTermination(60L, TimeUnit.SECONDS);
assertFalse(terminated);
} catch (InterruptedException ie) {
fail("InterruptedException");
}
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
}
/**
* Shutting down the cluster should act as the ExecutorService shutdown
*/
@Test(expected = RejectedExecutionException.class)
public void clusterShutdown() {
shutdownNodeFactory();
sleepSeconds(2);
assertNotNull(executor);
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
// new tasks must be rejected
Callable<String> task = new BasicTestCallable();
executor.submit(task);
}
// FIXME as soon as executor.getLocalExecutorStats() is implemented
//@Test
//public void executorServiceStats() throws Exception {
// final int executeCount = 10;
// LatchRunnable.latch = new CountDownLatch(executeCount);
// final LatchRunnable r = new LatchRunnable();
// for (int i = 0; i < executeCount; i++) {
// executor.execute(r);
// }
// assertOpenEventually(LatchRunnable.latch);
// final Future<Boolean> future = executor.submit(new SleepingTask(10));
// future.cancel(true);
// try {
// future.get();
// } catch (CancellationException ignored) {
// }
//
// assertTrueEventually(new AssertTask() {
// @Override
// public void run()
// throws Exception {
// final LocalExecutorStats stats = executor.getLocalExecutorStats();
// assertEquals(executeCount + 1, stats.getStartedTaskCount());
// assertEquals(executeCount, stats.getCompletedTaskCount());
// assertEquals(0, stats.getPendingTaskCount());
// assertEquals(1, stats.getCancelledTaskCount());
// }
// });
//}
static class LatchRunnable implements Runnable, Serializable {
static CountDownLatch latch;
@Override
public void run() {
latch.countDown();
}
}
}