001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.util.ejb;
023:
024: import java.util.Properties;
025:
026: import javax.naming.InitialContext;
027: import javax.rmi.PortableRemoteObject;
028:
029: import junit.framework.AssertionFailedError;
030: import junit.framework.TestCase;
031: import junit.framework.TestResult;
032:
033: /**
034: * An ejb test case is an extension to test case where the test is executed
035: * in the ejb server's virtual machine.
036: *
037: * Two new methods setUpEJB and tearDownEJB have been added. These methods
038: * work just like setUp and tearDown except they run in a sepperate transaction.
039: * The execution order is as follows:
040: * <pre>
041: * 1. setUpEJB (TX 1)
042: * 2. run (TX 2)
043: * 2.1. runBare
044: * 2.1.1 setUp
045: * 2.1.2 <your test method>
046: * 2.1.3 tearDown
047: * 3. ejbTearDown (TX 2)
048: * </pre>
049: *
050: * For an ejb test case to run successfully, the following must be setup:
051: * <pre>
052: * 1. The ejb test case class must be availabe to the client vm.
053: * 2. The ejb test case class must be availabe to the EJBTestRunner bean
054: * on the server.
055: * 3. The EJBTestRunnerHome must be bound to "ejb/EJBTestRunner" in the
056: * jndi context obtained from new InitialContext();
057: * 4. The EJBTestRunner bean must be configured as specified in the
058: * EJBTestRunner javadoc.
059: * </pre>
060: *
061: * @see EJBTestRunner
062: * @see junit.framework.TestCase
063: *
064: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
065: * @author <a href="mailto:scott@jboss.org">Scott Stark</a>
066: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
067: * @version $Revision: 61778 $
068: */
069: public class EJBTestCase extends TestCase {
070: private boolean serverSide = false;
071: protected Properties props;
072:
073: /**
074: * Constructs a test case that will run the method with the specified name.
075: * @param methodName the name of the method that will executed when this
076: * test is run
077: */
078: public EJBTestCase(String methodName) {
079: super (methodName);
080: }
081:
082: /**
083: * Sets the flag that is used to determine if the class
084: * is running on the server side.
085: * @param serverSide boolean flag that this class uses to determine
086: * if it's running on the server side.
087: */
088: public void setServerSide(boolean serverSide) {
089: this .serverSide = serverSide;
090: }
091:
092: /**
093: * Is this class running on the server side?
094: * @return true if this class is running on the server side
095: */
096: public boolean isServerSide() {
097: return serverSide;
098: }
099:
100: /** Allow EJBTestCase subclasses to override the EJBRunnerHome JNDI name
101: * @return The JNDI name of the EJBRunnerHome home interface binding. The
102: * default is "ejb/EJBTestRunner"
103: */
104: public String getEJBRunnerJndiName() {
105: return "ejb/EJBTestRunner";
106: }
107:
108: /**
109: * @return the properties associated with the test case
110: */
111: public Properties getProps() {
112: return props;
113: }
114:
115: /**
116: * @param props the properties associated with the test case
117: */
118: public void setProps(Properties props) {
119: this .props = props;
120: }
121:
122: public void run(TestResult result) {
123: ClassLoader oldClassLoader = null;
124: try {
125: // If we are on the server side, set the thread context class loader
126: // to the class loader that loaded this class. This fixes problems
127: // with the current implementation of the JUnit gui test runners class
128: // reloading logic. The gui relods the test classes with each run but
129: // does not set the context class loader so calls to Class.forName load
130: // the class in the wrong class loader.
131: if (!isServerSide()) {
132: oldClassLoader = Thread.currentThread()
133: .getContextClassLoader();
134: Thread.currentThread().setContextClassLoader(
135: getClass().getClassLoader());
136: }
137:
138: super .run(result);
139: } finally {
140: // be a good citizen, reset the context loader
141: if (oldClassLoader != null) {
142: Thread.currentThread().setContextClassLoader(
143: oldClassLoader);
144: }
145: }
146: }
147:
148: public void runBare() throws Throwable {
149: if (!isServerSide()) {
150: // We're not on the server side yet, invoke the test on the serverside.
151: EJBTestRunner testRunner = null;
152: try {
153: testRunner = getEJBTestRunner();
154: if (props != null)
155: testRunner.run(getClass().getName(), getName(),
156: props);
157: else
158: testRunner.run(getClass().getName(), getName());
159: } catch (RemoteTestException e) {
160: // if the remote test exception is from an assertion error
161: // rethrow it with a sub class of AssertionFailedError so it is
162: // picked up as a failure and not an error.
163: // The server has to throw sub classes of Error because that is the
164: // allowable scope of application exceptions. So
165: // AssertionFailedError which is an instance of error has to be
166: // wrapped in an exception.
167: Throwable remote = e.getRemoteThrowable();
168: if (remote instanceof AssertionFailedError) {
169: throw new RemoteAssertionFailedError(
170: (AssertionFailedError) remote, e
171: .getRemoteStackTrace());
172: }
173: throw e;
174: } finally {
175: // be a good citizen, drop my ref to the session bean.
176: if (testRunner != null) {
177: testRunner.remove();
178: }
179: }
180: } else {
181: // We're on the server side so, invoke the test the usual way.
182: super .runBare();
183: }
184: }
185:
186: /** Sets up the ejb test case. This method is called before
187: * each test is executed and is run in a private transaction.
188: * @param props the properties passed in from the client
189: * @throws Exception if a problem occures
190: */
191: public void setUpEJB(Properties props) throws Exception {
192: this .props = props;
193:
194: // JBAS-4144, hack to allow subclasses that originally
195: // used net.sourceforge.junitejb.EJBTestCase to still work.
196: setUpEJB();
197: }
198:
199: public void setUpEJB() throws Exception {
200: // empty
201: }
202:
203: /** Tears down the ejb test case. This method is called after
204: * each test is executed and is run in a private transaction.
205: * @param props the properties passed in from the client
206: * @throws Exception if a problem occures
207: */
208: public void tearDownEJB(Properties props) throws Exception {
209: // JBAS-4144, hack to allow subclasses that originally
210: // used net.sourceforge.junitejb.EJBTestCase to still work.
211: tearDownEJB();
212: }
213:
214: public void tearDownEJB() throws Exception {
215: // empty
216: }
217:
218: /**
219: * Looks up the ejb test runner home in JNDI (at "ejb/EJBTestRunner")
220: * and creates a new runner.
221: * @throws Exception if any problem happens
222: */
223: private EJBTestRunner getEJBTestRunner() throws Exception {
224: InitialContext jndiContext = new InitialContext();
225:
226: // Get a reference from this to the Bean's Home interface
227: String name = getEJBRunnerJndiName();
228: Object ref = jndiContext.lookup(name);
229: EJBTestRunnerHome runnerHome = (EJBTestRunnerHome) PortableRemoteObject
230: .narrow(ref, EJBTestRunnerHome.class);
231:
232: // create the test runner
233: return runnerHome.create();
234: }
235: }
|