001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.test;
046:
047: import junit.framework.Test;
048: import junit.framework.TestCase;
049: import junit.framework.TestSuite;
050: import org.apache.cactus.ServletTestCase;
051: import org.apache.cactus.ServletTestSuite;
052: import org.apache.cactus.WebRequest;
053: import org.apache.cactus.client.authentication.BasicAuthentication;
054: import org.apache.commons.logging.Log;
055: import org.obe.OBERuntimeException;
056: import org.obe.client.api.ClientConfig;
057: import org.obe.server.j2ee.ejb.EJBHelper;
058: import org.obe.xpdl.model.pkg.XPDLPackage;
059: import org.obe.xpdl.parser.XPDLParser;
060: import org.obe.xpdl.parser.XPDLParserException;
061: import org.obe.xpdl.parser.dom4j.Dom4JXPDLParser;
062:
063: import javax.transaction.Status;
064: import javax.transaction.SystemException;
065: import javax.transaction.UserTransaction;
066: import java.io.*;
067: import java.lang.reflect.Constructor;
068: import java.lang.reflect.InvocationTargetException;
069:
070: /**
071: * Abstract base test case that optionally manages user transactions.
072: *
073: * @author Adrian Price
074: */
075: public abstract class OBETestCase extends TestCase {
076: private static final Class[] CTOR_PARAM_TYPES = { String.class };
077: // These fields are static so they can be shared among test case instances.
078: private static final int BUF_SIZE = 4096;
079: private static final String USER_TRANSACTION = "java:comp/UserTransaction";
080: protected static UserTransaction _utx;
081:
082: // Subclasses can set these fields in their constructor or setUp() override.
083: protected String _principal;
084: protected String _credentials;
085: protected boolean _authenticateInternal;
086: protected boolean _runTestInTransaction;
087:
088: private boolean _utxStarted;
089:
090: // It is necessary to build the test suite explicitly because JUnit
091: // sometimes changes the order in which the tests are executed. The tests
092: // in this suite depend upon each other, and must therefore be executed in
093: // the correct sequence.
094: protected static Test junitSuite(Class testClass, String[] tests) {
095: try {
096: Constructor ctor = testClass
097: .getConstructor(CTOR_PARAM_TYPES);
098: TestSuite suite = new TestSuite(testClass.getName());
099: Object[] ctorArgs = { null };
100: for (int i = 0; i < tests.length; i++) {
101: ctorArgs[0] = tests[i];
102: suite.addTest((Test) ctor.newInstance(ctorArgs));
103: }
104: return suite;
105: } catch (NoSuchMethodException e) {
106: throw new OBERuntimeException(e);
107: } catch (IllegalAccessException e) {
108: throw new OBERuntimeException(e);
109: } catch (InvocationTargetException e) {
110: throw new OBERuntimeException(e);
111: } catch (InstantiationException e) {
112: throw new OBERuntimeException(e);
113: }
114: }
115:
116: // It is necessary to build the test suite explicitly because JUnit
117: // sometimes changes the order in which the tests are executed. The tests
118: // in this suite depend upon each other, and must therefore be executed in
119: // the correct sequence.
120: protected static Test cactusSuite(Class testClass, String[] tests) {
121: try {
122: Constructor ctor = testClass
123: .getConstructor(CTOR_PARAM_TYPES);
124: ServletTestSuite suite = new ServletTestSuite(testClass
125: .getName());
126: Object[] ctorArgs = { null };
127: for (int i = 0; i < tests.length; i++) {
128: ctorArgs[0] = tests[i];
129: suite.addTest(new ServletTestCase(tests[i], (Test) ctor
130: .newInstance(ctorArgs)));
131: }
132: return suite;
133: } catch (NoSuchMethodException e) {
134: throw new OBERuntimeException(e);
135: } catch (IllegalAccessException e) {
136: throw new OBERuntimeException(e);
137: } catch (InvocationTargetException e) {
138: throw new OBERuntimeException(e);
139: } catch (InstantiationException e) {
140: throw new OBERuntimeException(e);
141: }
142: }
143:
144: protected OBETestCase(String name) {
145: super (name);
146:
147: _authenticateInternal = Boolean
148: .getBoolean("obe.test.authenticate.internal");
149: _principal = ClientConfig.getPrincipal();
150: _credentials = ClientConfig.getCredentials();
151: }
152:
153: /**
154: * Generic beginXXX(WebRequest) method, to support HTTP authentication.
155: *
156: * @param request The web request.
157: */
158: public void begin(WebRequest request) {
159: if (_authenticateInternal && _principal != null) {
160: request.setRedirectorName("ServletRedirectorSecure");
161: request.setAuthentication(new BasicAuthentication(
162: _principal, _credentials));
163: }
164: }
165:
166: protected void setUp() throws Exception {
167: if (_runTestInTransaction)
168: beginTransaction();
169: }
170:
171: protected void tearDown() throws Exception {
172: if (_runTestInTransaction)
173: completeTransaction();
174: }
175:
176: protected abstract Log getLogger();
177:
178: /**
179: * Provides J2EE-compliant access to the UserTransaction object.
180: *
181: * @return The UserTransaction object.
182: */
183: protected UserTransaction getUserTransaction() {
184: if (_utx == null)
185: _utx = (UserTransaction) EJBHelper
186: .getJndiObject(USER_TRANSACTION);
187: return _utx;
188: }
189:
190: protected final void beginTransaction() {
191: UserTransaction utx = getUserTransaction();
192: if (utx != null) {
193: try {
194: int status = utx.getStatus();
195: switch (status) {
196: case Status.STATUS_ACTIVE:
197: log("Begin transaction request ignored");
198: break;
199: case Status.STATUS_COMMITTED:
200: case Status.STATUS_NO_TRANSACTION:
201: case Status.STATUS_UNKNOWN:
202: utx.begin();
203: _utxStarted = true;
204: break;
205: case Status.STATUS_COMMITTING:
206: case Status.STATUS_MARKED_ROLLBACK:
207: case Status.STATUS_PREPARED:
208: case Status.STATUS_PREPARING:
209: case Status.STATUS_ROLLEDBACK:
210: case Status.STATUS_ROLLING_BACK:
211: fail("Unable to begin transaction, status = "
212: + status);
213: break;
214: }
215: } catch (Exception e) {
216: log(e);
217: fail("Unable to begin transaction");
218: }
219: }
220: }
221:
222: protected void completeTransaction() {
223: if (_utxStarted) {
224: try {
225: UserTransaction utx = getUserTransaction();
226: int status = utx.getStatus();
227: switch (status) {
228: case Status.STATUS_ACTIVE:
229: utx.commit();
230: break;
231: case Status.STATUS_MARKED_ROLLBACK:
232: utx.rollback();
233: break;
234: case Status.STATUS_COMMITTED:
235: case Status.STATUS_COMMITTING:
236: case Status.STATUS_ROLLEDBACK:
237: case Status.STATUS_ROLLING_BACK:
238: log("Complete transaction request ignored, status = "
239: + status);
240: break;
241: default:
242: log("Unable to complete transaction, status = "
243: + status);
244: }
245: } catch (Exception e) {
246: log("Error completing transaction: " + e);
247: fail("Unable to complete transaction");
248: } finally {
249: _utxStarted = false;
250: }
251: } else {
252: log("Complete transaction request ignored");
253: }
254: }
255:
256: protected final void commitTransaction() {
257: if (_utxStarted) {
258: try {
259: UserTransaction utx = getUserTransaction();
260: int status = utx.getStatus();
261: switch (status) {
262: case Status.STATUS_ACTIVE:
263: utx.commit();
264: break;
265: case Status.STATUS_COMMITTED:
266: case Status.STATUS_COMMITTING:
267: log("Commit transaction request ignored, status = "
268: + status);
269: break;
270: case Status.STATUS_NO_TRANSACTION:
271: case Status.STATUS_UNKNOWN:
272: case Status.STATUS_MARKED_ROLLBACK:
273: case Status.STATUS_PREPARED:
274: case Status.STATUS_PREPARING:
275: case Status.STATUS_ROLLEDBACK:
276: case Status.STATUS_ROLLING_BACK:
277: fail("Unable to commit user transaction, status = "
278: + status);
279: break;
280: }
281: } catch (Exception e) {
282: log("Error committing transaction: " + e);
283: fail("Unable to commit user transaction");
284: } finally {
285: _utxStarted = false;
286: }
287: } else {
288: log("Commit transaction request ignored");
289: }
290: }
291:
292: protected final void rollbackTransaction() {
293: if (_utxStarted) {
294: try {
295: UserTransaction utx = getUserTransaction();
296: int status = utx.getStatus();
297: switch (status) {
298: case Status.STATUS_ACTIVE:
299: case Status.STATUS_MARKED_ROLLBACK:
300: utx.rollback();
301: break;
302: case Status.STATUS_ROLLEDBACK:
303: case Status.STATUS_ROLLING_BACK:
304: log("Commit transaction request ignored, status = "
305: + status);
306: break;
307: case Status.STATUS_COMMITTED:
308: case Status.STATUS_COMMITTING:
309: case Status.STATUS_NO_TRANSACTION:
310: case Status.STATUS_UNKNOWN:
311: case Status.STATUS_PREPARED:
312: case Status.STATUS_PREPARING:
313: fail("Unable to rollback user transaction: status = "
314: + status);
315: break;
316: }
317: } catch (SystemException e) {
318: log("Error rolling back transaction: " + e);
319: fail("Unable to rollback user transaction");
320: } finally {
321: _utxStarted = false;
322: }
323: } else {
324: log("Rollback transaction request ignored");
325: }
326: }
327:
328: protected void log(Object x) {
329: getLogger().info(getName() + ": " + x);
330: }
331:
332: protected static String readFile(String fileName)
333: throws IOException {
334: ClassLoader cl = WMClientTest.class.getClassLoader();
335: InputStream in = cl.getResourceAsStream(fileName);
336: Reader reader = new InputStreamReader(in);
337: StringBuffer sbuf = new StringBuffer(in.available());
338: char[] cbuf = new char[BUF_SIZE];
339: int offset = 0;
340: int count;
341: do {
342: count = reader.read(cbuf, offset, cbuf.length);
343: if (count > 0)
344: sbuf.append(cbuf, 0, count);
345: } while (count > 0);
346: in.close();
347: return sbuf.toString();
348: }
349:
350: protected XPDLPackage readPackage(String content)
351: throws XPDLParserException, IOException {
352:
353: assertNotNull("Package content is null;", content);
354: XPDLParser parser = new Dom4JXPDLParser();
355: return parser.parse(new StringReader(content));
356: }
357: }
|