/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.ajax4jsf.tests;
import javax.faces.context.FacesContext;
import junit.framework.AssertionFailedError;
import junit.framework.TestResult;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.context.AjaxContextImpl;
import org.apache.shale.test.mock.MockFacesContext;
import org.apache.shale.test.mock.MockHttpServletRequest;
import org.apache.shale.test.mock.MockHttpServletResponse;
import org.apache.shale.test.mock.MockHttpSession;
/**
* @author asmirnov@exadel.com (latest modification by $Author: ishabalov $)
* @version $Revision: 1.1.2.3 $ $Date: 2007/02/20 20:58:08 $
*
/**
* A multi-threaded JUnit test case, with setup faces environment.
* To perform test cases that spin off threads to do tests: <p>
* <UL>
* <LI>Extend <code>MultiThreadedTestCase</code>
* <LI>Write your tests cases as normal except for when you want to spin off threads.
* <LI>When you want to spin off threads:
* <UL>
* <LI>Instead of implementing <code>Runnable</code> extend <code>MultiThreadedTestCase.TestCaseRunnable</code>.
* <LI>Define <code>runTestCase ()</code> to do your test, you may call <code>fail (), assert ()</code> etc. and throw
* exceptions with impunity.
* <LI>Handle thread interrupts by finishing.
* </UL>
* <LI>Instantiate all the runnables (one for each thread you wish to spawn) and pass an array of them
* to <code>runTestCaseRunnables ()</code>.
* </UL>
* That's it. An example is below:
* <PRE>
* public class MTTest extends ThreadedVcpJsfTestCase
* {
* MTTest (String s) { super (s); }
* public class CounterThread extends TestCaseRunnable
* {
* public void runTestCase (FacesContext context) throws Throwable
* {
* for (int i = 0; i < 1000; i++)
* {
* System.out.println ("Counter Thread: " + Thread.currentThread () + " : " + i);
* // Do some testing...
* if (Thread.currentThread ().isInterrupted ()) {
* return;
* }
* }
* }
* }
*
* public void test1 ()
* {
* TestCaseRunnable tct [] = new TestCaseRunnable [5];
* for (int i = 0; i < 5; i++)
* {
* tct[i] = new CounterThread ();
* }
* runTestCaseRunnables (tct);
* }
* }
* </PRE>
* <BR><STRONG>Category: Test</STRONG>
* <BR><STRONG>Not guaranteed to be thread safe.</STRONG>
*/
public class AbstractThreadedAjax4JsfTestCase extends AbstractAjax4JsfTestCase {
/**
* The threads that are executing.
*/
private Thread threads[] = null;
/**
* The tests TestResult.*/
private TestResult testResult = null;
/**
* Simple constructor.
*/
public AbstractThreadedAjax4JsfTestCase(String s) {
super(s);
}
/**
* Interrupt the running threads.
*/
public void interruptThreads() {
if(threads != null) {
for(int i = 0;i < threads.length;i++) {
threads[i].interrupt();
}
}
}
/**
* Override run so we can squirrel away the test result.*/
public void run(final TestResult result) {
testResult = result;
super.run(result);
testResult = null;
}
/**
* Create instances of classes and run threads with it.
* @param clazz - class of test thread implementation.
* @param numThreads - number of threads to run.
* @throws InstantiationException
* @throws IllegalAccessException
*/
protected void runTestCaseThreads(Class clazz, int numThreads) {
TestCaseRunnable[] runnables = new TestCaseRunnable[numThreads];
for (int i = 0; i < runnables.length; i++) {
try {
runnables[i]= (TestCaseRunnable) clazz.newInstance();
} catch (Exception e) {
testResult.addError(this, e);
return;
}
}
runTestCaseRunnables(runnables);
}
/**
* Run the test case threads.
* @param runnables - array with instances of {@link TestCaseRunnable} with concrete tests
*/
protected void runTestCaseRunnables (final TestCaseRunnable[] runnables) {
if(runnables == null) {
throw new IllegalArgumentException("runnables is null");
}
threads = new Thread[runnables.length];
for(int i = 0;i < threads.length;i++) {
threads[i] = new Thread(runnables[i]);
}
for(int i = 0;i < threads.length;i++) {
threads[i].start();
}
try {
for(int i = 0;i < threads.length;i++) {
threads[i].join();
}
}
catch(InterruptedException ignore) {
System.out.println("Thread join interrupted.");
}
threads = null;
}
/**
* Handle an exception. Since multiple threads won't have their
* exceptions caught the threads must manually catch them and call
* <code>handleException ()</code>.
* @param t Exception to handle.*/
private void handleException(final Throwable t) {
synchronized(testResult) {
if(t instanceof AssertionFailedError) {
testResult.addFailure(this, (AssertionFailedError)t);
}
else {
testResult.addError(this, t);
}
}
}
/**
* A test case thread. Override runTestCase () and define
* behaviour of test in there.*/
public abstract class TestCaseRunnable implements Runnable {
/**
* Override this to define the test*/
public abstract void runTestCase(FacesContext context)
throws Throwable;
/**
* Run the test in an environment where
* we can handle the exceptions generated by the test method.*/
public void run() {
FacesContext context = null;
try {
context = createFacesContext();
runTestCase(context);
}
catch(Throwable t) /* Any other exception we handle and then we interrupt the other threads.*/ {
handleException(t);
interruptThreads();
} finally {
if(null != context) {
context.release();
}
}
}
}
/**
* Create instance of faces context for current thread.
* @return
*/
protected FacesContext createFacesContext() {
MockHttpSession tsession = new MockHttpSession();
MockHttpServletRequest trequest = new MockHttpServletRequest(tsession);
trequest.setAttribute(AjaxContext.AJAX_CONTEXT_KEY, new AjaxContextImpl());
MockHttpServletResponse tresponse = new MockHttpServletResponse();
MockFacesContext tfacesContext = (MockFacesContext)
facesContextFactory.getFacesContext(servletContext,
trequest,
tresponse,
lifecycle);
tfacesContext.setApplication(application);
tfacesContext.setViewRoot(application.getViewHandler().createView(facesContext, facesContext.getViewRoot().getViewId()));
return tfacesContext;
}
}