/*******************************************************************************
* Copyright (c) 2012, 2014 Wind River Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the terms
* of the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.tests.concurrent;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.tcf.te.runtime.concurrent.Executors;
import org.eclipse.tcf.te.runtime.concurrent.executors.AbstractDelegatingExecutorService;
import org.eclipse.tcf.te.runtime.concurrent.interfaces.IExecutor;
import org.eclipse.tcf.te.runtime.concurrent.interfaces.INestableExecutor;
import org.eclipse.tcf.te.runtime.concurrent.interfaces.ISingleThreadedExecutor;
import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil;
import org.eclipse.tcf.te.tests.CoreTestCase;
/**
* Concurrent test cases.
*/
public class ConcurrentTestCase extends CoreTestCase {
/**
* Provides a test suite to the caller which combines all single
* test bundled within this category.
*
* @return Test suite containing all test for this test category.
*/
public static Test getTestSuite() {
TestSuite testSuite = new TestSuite("Test concurrent framework"); //$NON-NLS-1$
// add ourself to the test suite
testSuite.addTestSuite(ConcurrentTestCase.class);
return testSuite;
}
//***** BEGIN SECTION: Single test methods *****
//NOTE: All method which represents a single test case must
// start with 'test'!
public void testPrivateOrInternalClasses() {
ExecutorsUtil executorsUtil = new ExecutorsUtil();
assertNotNull(executorsUtil);
try {
Constructor<?>[] constructors = Executors.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
assertNotNull("Failed to get default constructor of Executors!", constructors); //$NON-NLS-1$
constructor.setAccessible(true);
Object instance = constructor.newInstance((Object[])null);
assertNotNull("Failed to invoke default constructor of Executors!", instance); //$NON-NLS-1$
}
} catch (Exception e) {}
}
public void testSingleThreadExecutorService() {
// Get the execution service instance
IExecutor executor = Executors.newExecutor("org.eclipse.tcf.te.runtime.concurrent.executors.singleThreaded"); //$NON-NLS-1$
assertNotNull("Failed to get executor instance!", executor); //$NON-NLS-1$
assertTrue("Executor not implementing ISingleThreadedExecutor", executor instanceof ISingleThreadedExecutor); //$NON-NLS-1$
final ISingleThreadedExecutor singleThreadedExecutor = (ISingleThreadedExecutor)executor;
// Within here, we have to be outside the execution thread
assertFalse("Is execution thread but should not!", singleThreadedExecutor.isExecutorThread()); //$NON-NLS-1$
// Create a runnable to be executed with the executor thread
final Boolean[] result = new Boolean[1];
result[0] = Boolean.FALSE;
Runnable runnable = new Runnable() {
@Override
public void run() {
result[0] = Boolean.valueOf(singleThreadedExecutor.isExecutorThread());
}
};
// Execute
singleThreadedExecutor.execute(runnable);
// Give it a little bit time to run
AtomicInteger counter = new AtomicInteger();
while (Boolean.FALSE.equals(result[0]) && counter.getAndIncrement() < 20) {
try { Thread.sleep(100); } catch (InterruptedException e) { /* ignored on purpose */ }
}
assertTrue("Runnable not executed within the executor thread!", result[0].booleanValue()); //$NON-NLS-1$
// If the executor is implementing the ExecutorService interface, we can shutdown the executor
if (executor instanceof ExecutorService) {
ExecutorService service = (ExecutorService)executor;
// Shutdown the executor service
assertFalse("Executor service instance is marked as shutdowned, but should not!", service.isShutdown()); //$NON-NLS-1$
service.shutdown();
assertTrue("Executor service instance is not marked as shutdowned, but should!", service.isShutdown()); //$NON-NLS-1$
}
// Get the shared executor service instance
IExecutor sharedExecutor = Executors.getSharedExecutor("org.eclipse.tcf.te.runtime.concurrent.executors.singleThreaded"); //$NON-NLS-1$
assertNotNull("Failed to get shared executor instance!"); //$NON-NLS-1$
assertNotSame("Shared executor instance is same instance as the newly created executor!", executor, sharedExecutor); //$NON-NLS-1$
// If the shared executor service is not a nestable service, our tests are done here
if (!(sharedExecutor instanceof INestableExecutor)) return;
// Test the nestable executor functionality
final INestableExecutor nestedExecutor = (INestableExecutor)sharedExecutor;
result[0] = Boolean.FALSE;
final List<String> result2 = new ArrayList<String>();
// Single threaded and nested --> means maxDepth == 1
assertEquals("Single threaded nested executor has invalid maxDepth set!", 1, nestedExecutor.getMaxDepth()); //$NON-NLS-1$
Runnable runnable1 = new Runnable() {
@Override
public void run() {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
result2.add("1"); //$NON-NLS-1$
while (nestedExecutor.readAndExecute()) {}
result2.add("3"); //$NON-NLS-1$
result[0] = Boolean.TRUE;
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
result2.add("2"); //$NON-NLS-1$
}
};
nestedExecutor.execute(runnable1);
nestedExecutor.execute(runnable2);
// Give it a little bit time to run
counter = new AtomicInteger();
while (Boolean.FALSE.equals(result[0]) && counter.getAndIncrement() < 40) {
try { Thread.sleep(100); } catch (InterruptedException e) { /* ignored on purpose */ }
}
assertTrue("Runnable not executed within the executor thread!", result[0].booleanValue()); //$NON-NLS-1$
// The result list should contain "1", "2", "3" in this order.
assertEquals("Unexpected result list size!", 3, result2.size()); //$NON-NLS-1$
assertEquals("Unexpected result at position 1!", "1", result2.get(0)); //$NON-NLS-1$ //$NON-NLS-2$
assertEquals("Unexpected result at position 2!", "2", result2.get(1)); //$NON-NLS-1$ //$NON-NLS-2$
assertEquals("Unexpected result at position 3!", "3", result2.get(2)); //$NON-NLS-1$ //$NON-NLS-2$
// Get all shared executor service instances
IExecutor[] executors = Executors.getAllSharedExecutors();
assertTrue("Unexpected emply list returned!", executors.length > 0); //$NON-NLS-1$
}
class InternalTestAbstractDelegatingExecutorServiceImplementation extends AbstractDelegatingExecutorService {
final Map<String, Object> fResultMap;
/**
* Constructor.
*
*/
public InternalTestAbstractDelegatingExecutorServiceImplementation(Map<String, Object> resultMap) {
super();
assertNotNull("Invalid constructor parameter resultMap. Must not be null!", resultMap); //$NON-NLS-1$
fResultMap = resultMap;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.concurrent.executors.AbstractDelegatingExecutorService#createExecutorServiceDelegate()
*/
@Override
protected ExecutorService createExecutorServiceDelegate() {
return new ExecutorService() {
@Override
public void execute(Runnable command) {
fResultMap.put("ExecutorService.execute", Boolean.TRUE); //$NON-NLS-1$
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
fResultMap.put("ExecutorService.submit1", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public Future<?> submit(Runnable task) {
fResultMap.put("ExecutorService.submit2", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public <T> Future<T> submit(Callable<T> task) {
fResultMap.put("ExecutorService.submit3", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public List<Runnable> shutdownNow() {
fResultMap.put("ExecutorService.shutdownNow", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public void shutdown() {
fResultMap.put("ExecutorService.shutdown", Boolean.TRUE); //$NON-NLS-1$
}
@Override
public boolean isTerminated() {
fResultMap.put("ExecutorService.isTerminated", Boolean.TRUE); //$NON-NLS-1$
return false;
}
@Override
public boolean isShutdown() {
fResultMap.put("ExecutorService.isShutdown", Boolean.TRUE); //$NON-NLS-1$
return false;
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
fResultMap.put("ExecutorService.invokeAny1", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
fResultMap.put("ExecutorService.invokeAny2", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
fResultMap.put("ExecutorService.invokeAll1", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
fResultMap.put("ExecutorService.invokeAll2", Boolean.TRUE); //$NON-NLS-1$
return null;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
fResultMap.put("ExecutorService.awaitTermination", Boolean.TRUE); //$NON-NLS-1$
return false;
}
};
}
}
public void testAbstractDelegatingExecutorService() {
// To test the AbstractDelegatingExecutorService, we create a special
// executor storing the signature of the invoked method into a map
// Create the result map
final Map<String, Object> result = new HashMap<String, Object>();
// Construct the test service
AbstractDelegatingExecutorService service = new InternalTestAbstractDelegatingExecutorServiceImplementation(result);
service.initializeExecutorServiceDelegate();
assertNotNull("Failed to instanciate and to initialize the test executor service implementation!", service); //$NON-NLS-1$
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
Callable<Object> callable = new Callable<Object>() {
@Override
public Object call() throws Exception {
return null;
}
};
List<Callable<Object>> callables = new ArrayList<Callable<Object>>();
callables.add(callable);
// Invoke each method now
service.execute(runnable);
service.submit(callable);
service.submit(runnable);
service.submit(runnable, new Object());
service.shutdown();
service.shutdownNow();
service.isShutdown();
service.isTerminated();
try {
service.invokeAny(callables);
service.invokeAny(callables, 0, TimeUnit.MICROSECONDS);
service.invokeAll(callables);
service.invokeAll(callables, 0, TimeUnit.MICROSECONDS);
service.awaitTermination(0, TimeUnit.MICROSECONDS);
} catch (Exception e) {}
assertTrue(((Boolean)result.get("ExecutorService.execute")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.submit1")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.submit2")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.submit3")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.shutdown")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.shutdownNow")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.isShutdown")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.isTerminated")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.invokeAny1")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.invokeAny2")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.invokeAll1")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.invokeAll2")).booleanValue()); //$NON-NLS-1$
assertTrue(((Boolean)result.get("ExecutorService.awaitTermination")).booleanValue()); //$NON-NLS-1$
}
//***** END SECTION: Single test methods *****
}