/**
* EasyBeans
* Copyright (C) 2012 Bull S.A.S.
* Contact: easybeans@ow2.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id$
* --------------------------------------------------------------------------
*/
package org.ow2.easybeans.itests.tests;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.ejb.ConcurrentAccessException;
import javax.ejb.ConcurrentAccessTimeoutException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.ow2.easybeans.application.accesstimeout.IAccessTimeout;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @author Florent Benoit
*/
public class TestAccessTimeout {
/**
* MAX wait time for the executor.
*/
private static final long MAX_WAIT_TIME = 30;
/**
* Stateful test Bean.
*/
private IAccessTimeout annotationStatefulBean1 = null;
/**
* Stateful test Bean.
*/
private IAccessTimeout annotationStatefulBean2 = null;
/**
* Stateful test Bean.
*/
private IAccessTimeout annotationStatefulBean3 = null;
/**
* Singleton test Bean.
*/
private IAccessTimeout annotationSingletonBean1 = null;
/**
* Singleton test Bean.
*/
private IAccessTimeout annotationSingletonBean2 = null;
/**
* Singleton test Bean.
*/
private IAccessTimeout annotationSingletonBean3 = null;
/**
* Executor service.
*/
private ExecutorService executorService = null;
@BeforeClass
public void setup() throws NamingException {
this.annotationStatefulBean1 = (IAccessTimeout) new InitialContext().lookup("AnnotationStatefulAccessTimeout");
this.annotationStatefulBean2 = (IAccessTimeout) new InitialContext().lookup("AnnotationStatefulAccessTimeout");
this.annotationStatefulBean3 = (IAccessTimeout) new InitialContext().lookup("AnnotationStatefulAccessTimeout");
this.annotationSingletonBean1 = (IAccessTimeout) new InitialContext().lookup("AnnotationSingletonAccessTimeout");
this.annotationSingletonBean2 = (IAccessTimeout) new InitialContext().lookup("AnnotationSingletonAccessTimeout2");
this.annotationSingletonBean3 = (IAccessTimeout) new InitialContext().lookup("AnnotationSingletonAccessTimeout3");
this.executorService = Executors.newFixedThreadPool(50);
}
@AfterClass
public void stop() throws InterruptedException {
this.executorService.shutdown();
this.executorService.awaitTermination(MAX_WAIT_TIME, TimeUnit.SECONDS);
}
@Test
public void testNoConcurrentStatefulAccessTimeout() throws InterruptedException {
testNoConcurrentAccessTimeout(this.annotationStatefulBean1);
}
@Test
public void testStatefulDefaultTimeout() throws InterruptedException {
testDefaultTimeout(this.annotationStatefulBean2);
}
@Test
public void testStatefulTimeoutException() throws InterruptedException {
testLongMethodTimeoutError(this.annotationStatefulBean3);
}
@Test
public void testNoConcurrentSingletonAccessTimeout() throws InterruptedException {
testNoConcurrentAccessTimeout(this.annotationSingletonBean1);
}
@Test
public void testSingletonDefaultTimeout() throws InterruptedException {
testDefaultTimeout(this.annotationSingletonBean2);
}
@Test
public void testSingletonTimeoutException() throws InterruptedException {
testLongMethodTimeoutError(this.annotationSingletonBean3);
}
public void testNoConcurrentAccessTimeout(final IAccessTimeout bean) throws InterruptedException {
List<Future<String>> lst = new ArrayList<Future<String>>();
NoTimeoutBeanCallable call1 = new NoTimeoutBeanCallable(bean, "Florent");
NoTimeoutBeanCallable call2 = new NoTimeoutBeanCallable(bean, "Benoit");
lst.add(this.executorService.submit(call1));
// wait before submitting the new call
Thread.sleep(200L);
lst.add(this.executorService.submit(call2));
try {
Assert.assertEquals(lst.get(0).get(), "Florent");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Not expected", e);
}
try {
String value = lst.get(1).get();
Assert.fail("Shouldn't be able to get the value due to no access timeout. Found '" + value + "'");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
// Check cause
Throwable t = e.getCause();
if (!(t instanceof ConcurrentAccessException)) {
throw new IllegalStateException("Check the given exception", e);
}
}
}
/**
* Try to invoke the given bean and check that there is a timeout when there are concurrent threads.
* @param bean the bean instance to check
* @throws InterruptedException if executor service fails
*/
public void testDefaultTimeout(final IAccessTimeout bean) throws InterruptedException {
List<Future<String>> lst = new ArrayList<Future<String>>();
DefaultTimeoutBeanCallable call1 = new DefaultTimeoutBeanCallable(bean, "Florent");
DefaultTimeoutBeanCallable call2 = new DefaultTimeoutBeanCallable(bean, "Benoit");
lst.add(this.executorService.submit(call1));
// wait before submitting the new call
Thread.sleep(200L);
lst.add(this.executorService.submit(call2));
try {
Assert.assertEquals(lst.get(0).get(), "Florent");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Not expected", e);
}
// Timeout should have been passed (processing time of 2s < 6s of the
// method timeout)
try {
Assert.assertEquals(lst.get(1).get(), "Benoit");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Not expected", e);
}
}
/**
* Try to invoke the given bean and check that there is a timeout when there are concurrent threads.
* @param bean the bean instance to check
* @throws InterruptedException if executor service fails
*/
public void testLongMethodTimeoutError(final IAccessTimeout bean) throws InterruptedException {
List<Future<String>> lst = new ArrayList<Future<String>>();
LongTimeoutBeanCallable call1 = new LongTimeoutBeanCallable(bean, "Florent");
LongTimeoutBeanCallable call2 = new LongTimeoutBeanCallable(bean, "Benoit");
lst.add(this.executorService.submit(call1));
// wait before submitting the new call
Thread.sleep(200L);
lst.add(this.executorService.submit(call2));
try {
Assert.assertEquals(lst.get(0).get(), "Florent");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Not expected", e);
}
// Timeout should not been passed (processing time > waiting time)
// method timeout)
try {
String value = lst.get(1).get();
Assert.fail("Shouldn't be able to get the value due to access timeout. Found '" + value + "'");
} catch (InterruptedException e) {
throw new IllegalStateException("Not expected", e);
} catch (ExecutionException e) {
// Check cause
Throwable t = e.getCause();
if (!(t instanceof ConcurrentAccessTimeoutException)) {
throw new IllegalStateException("Check the given exception", e);
}
}
}
public class DefaultTimeoutBeanCallable implements Callable<String> {
private IAccessTimeout bean = null;
private String value = null;
public DefaultTimeoutBeanCallable(final IAccessTimeout bean, final String value) {
this.bean = bean;
this.value = value;
}
public String call() throws Exception {
return this.bean.defaultTimeout(this.value);
}
}
public class NoTimeoutBeanCallable implements Callable<String> {
private IAccessTimeout bean = null;
private String value = null;
public NoTimeoutBeanCallable(final IAccessTimeout bean, final String value) {
this.bean = bean;
this.value = value;
}
public String call() throws Exception {
return this.bean.noTimeout(this.value);
}
}
public class LongTimeoutBeanCallable implements Callable<String> {
private IAccessTimeout bean = null;
private String value = null;
public LongTimeoutBeanCallable(final IAccessTimeout bean, final String value) {
this.bean = bean;
this.value = value;
}
public String call() throws Exception {
return this.bean.longMethod(this.value);
}
}
}