001: package com.bm.testsuite;
002:
003: import java.sql.DataTruncation;
004: import java.util.ArrayList;
005: import java.util.Collection;
006: import java.util.List;
007:
008: import javax.persistence.EntityManager;
009: import javax.persistence.EntityManagerFactory;
010: import javax.persistence.EntityTransaction;
011:
012: import org.apache.log4j.Logger;
013: import org.hibernate.exception.GenericJDBCException;
014:
015: import com.bm.cfg.Ejb3UnitCfg;
016: import com.bm.creators.EntityBeanCreator;
017: import com.bm.datagen.Generator;
018: import com.bm.datagen.relation.EntityRelation;
019: import com.bm.introspectors.EntityBeanIntrospector;
020: import com.bm.introspectors.Property;
021: import com.bm.utils.BeanEqualsTester;
022: import com.bm.utils.NullableSetter;
023: import com.bm.utils.SimpleGetterSetterTest;
024: import com.bm.utils.UndoScriptGenerator;
025:
026: /**
027: * This class is the base executes for all entity beans the automated test
028: * cases.
029: *
030: * @author Daniel Wiese
031: * @param <T> -
032: * the type of the entity bean
033: * @since 07.10.2005
034: */
035: public abstract class BaseEntityFixture<T> extends BaseTest {
036:
037: private static final Logger log = Logger
038: .getLogger(BaseEntityFixture.class);
039:
040: private static final int BEANS_TO_CREATE = 50;
041:
042: private static EntityManagerFactory emf;
043:
044: private Class<T> baseClass;
045:
046: private final EntityBeanIntrospector<T> intro;
047:
048: private final EntityBeanCreator<T> creator;
049:
050: /** this field is setted before every test * */
051: private UndoScriptGenerator<T> undo = null;
052:
053: private EntityManager manager = null;
054:
055: private boolean lastTestRollbacked = false;
056:
057: /**
058: * Default constructor.
059: *
060: * @param entityToTest -
061: * the entity to test
062: */
063: public BaseEntityFixture(Class<T> entityToTest) {
064: final List<Class<? extends Object>> entitiesToTest = new ArrayList<Class<? extends Object>>();
065: entitiesToTest.add(entityToTest);
066: this .initEntityManagerFactory(entitiesToTest);
067: this .baseClass = entityToTest;
068: this .intro = new EntityBeanIntrospector<T>(this .baseClass);
069: this .creator = new EntityBeanCreator<T>(intro, this .baseClass);
070: }
071:
072: /**
073: * Additional constructor.
074: *
075: * @param entityToTest -
076: * the entity to test
077: * @param additionalGenerators
078: * -a dditional generators (plug in)
079: */
080: @SuppressWarnings("unchecked")
081: public BaseEntityFixture(Class<T> entityToTest,
082: Generator[] additionalGenerators) {
083: final List<Class<? extends Object>> entitiesToTest = new ArrayList<Class<? extends Object>>();
084: // add the currenbt class
085: entitiesToTest.add(entityToTest);
086:
087: // register additional generators
088: final List<Generator> currentGenList = new ArrayList<Generator>();
089: for (Generator aktGen : additionalGenerators) {
090: currentGenList.add(aktGen);
091: // look for additional, releated entity beans
092: if (aktGen instanceof EntityRelation) {
093: final EntityRelation<Object> er = (EntityRelation<Object>) aktGen;
094: entitiesToTest.add(er.getUsedBeans());
095: }
096: }
097:
098: this .initEntityManagerFactory(entitiesToTest);
099: this .baseClass = entityToTest;
100: this .intro = new EntityBeanIntrospector<T>(this .baseClass);
101:
102: this .creator = new EntityBeanCreator<T>(intro, this .baseClass,
103: currentGenList);
104:
105: }
106:
107: private void initEntityManagerFactory(
108: Collection<Class<? extends Object>> entitiesToTest) {
109: Ejb3UnitCfg.addEntytiesToTest(entitiesToTest);
110: }
111:
112: /**
113: * @see junit.framework.TestCase#setUp()
114: */
115: @Override
116: protected void setUp() throws Exception {
117: super .setUp();
118: log.debug("Setting up BaseEntityTest");
119: emf = Ejb3UnitCfg.getConfiguration().getEntityManagerFactory();
120: this .undo = new UndoScriptGenerator<T>(intro);
121: this .manager = emf.createEntityManager();
122: this .lastTestRollbacked = false;
123: this .creator.prepare();
124: }
125:
126: /**
127: * @see junit.framework.TestCase#tearDown()
128: */
129: @Override
130: protected void tearDown() throws Exception {
131: super .tearDown();
132: this .creator.cleanup();
133: log.debug("Cleaning database from previous test");
134: // check if the manager is open
135: if (this .manager == null || !this .manager.isOpen()) {
136: this .manager = emf.createEntityManager();
137: }
138:
139: try {
140: // only delete objects if the test was not rollbacked
141: if (!this .lastTestRollbacked) {
142: if (Ejb3UnitCfg.getConfiguration().isInMemory()) {
143: this .undo.deleteAllDataInAllUsedTables(manager);
144: } else {
145: // delete all beans in one single transaction
146: EntityTransaction tx = manager.getTransaction();
147: tx.begin();
148: List<Object> createdObjects = this .undo
149: .getCreatedObjects();
150: for (Object beanToDelete : createdObjects) {
151: Object attached = this .manager
152: .merge(beanToDelete);
153: this .manager.remove(attached);
154: }
155:
156: // the transaction must be committed
157: tx.commit();
158: }
159: } else {
160: log
161: .info("Nothing to cleanup because last test was rollbacked");
162: }
163: // close the manager
164: } catch (RuntimeException e) {
165: log.error("ATTENTION Could not delete all contents!!!!");
166: log
167: .error("Please execute the following SQL scripte manually:");
168: log.error("-----------SQL Script begin-----------------");
169: StringBuilder sb = new StringBuilder();
170: sb.append("\n");
171: for (String sql : this .undo.getSQLUndoStatements()) {
172: sb.append(sql).append("\n");
173: }
174: log.error(sb.toString());
175: log.error("-----------SQL Script end-------------------");
176: // rethrow the error
177: throw e;
178: } finally {
179: manager.close();
180: }
181: }
182:
183: /**
184: * This test writes n random generated beans into the database.
185: *
186: * @throws Exception -
187: * in an error case
188: */
189: public void testWrite() throws Exception {
190: EntityTransaction tx = manager.getTransaction();
191: T created = null;
192: try {
193: tx.begin();
194:
195: for (int i = 0; i < BEANS_TO_CREATE; i++) {
196: created = creator.createBeanInstance();
197: manager.persist(created);
198: undo.protokollCreate(created);
199: }
200:
201: // the transaction must be committed
202: tx.commit();
203: } catch (RuntimeException e) {
204: tx.rollback();
205: this .lastTestRollbacked = true;
206: // throw error only in an unknown exception case
207: if (!this .analyseException(e, created)) {
208: throw e;
209: }
210: } finally {
211: this .manager.close();
212: }
213:
214: }
215:
216: /**
217: * This test tests the simpe getter-/ setter methods.
218: *
219: */
220: public void testGetterSetter() {
221: T created = creator.createBeanInstance();
222: final SimpleGetterSetterTest test = new SimpleGetterSetterTest(
223: created);
224: test.testGetterSetter();
225: }
226:
227: /**
228: * This test writes n random generated beans into the database - all
229: * nullable fields are setted to null.
230: *
231: * @throws Exception -
232: * in an error case
233: */
234: public void disabled_testWriteWithNullFields() throws Exception {
235: EntityTransaction tx = manager.getTransaction();
236: T created = null;
237: try {
238: tx.begin();
239:
240: for (int i = 0; i < BEANS_TO_CREATE; i++) {
241: created = creator.createBeanInstance();
242: NullableSetter.setFieldsToNull(created, this .intro);
243: manager.persist(created);
244: undo.protokollCreate(created);
245: }
246:
247: // the transaction must be committed
248: tx.commit();
249: } catch (RuntimeException e) {
250: tx.rollback();
251: this .lastTestRollbacked = true;
252: // throwan error only in an unknown exception case
253: if (!this .analyseException(e, created)) {
254: throw e;
255: }
256: } finally {
257: this .manager.close();
258: }
259:
260: }
261:
262: /**
263: * This test writes n random generated beans into the database Reads all
264: * beans agin form the database and test if the reded beans are equal 1) by
265: * introspectin all persistent fields 2) by callung the eqals method.
266: *
267: * Additionaly the hash-code implementation will be checked
268: *
269: * @throws Exception -
270: * in an error case
271: */
272: public void testWriteRead() throws Exception {
273: EntityTransaction tx = manager.getTransaction();
274: final List<T> beansCreated = new ArrayList<T>();
275: final List<T> beansReaded = new ArrayList<T>();
276: T created = null;
277: try {
278: tx.begin();
279:
280: for (int i = 0; i < BEANS_TO_CREATE; i++) {
281: created = creator.createBeanInstance();
282: manager.persist(created);
283: undo.protokollCreate(created);
284: beansCreated.add(created);
285: }
286:
287: // the transaction must be committed
288: tx.commit();
289:
290: } catch (RuntimeException e) {
291: if (tx.isActive()) {
292: tx.rollback();
293: }
294: this .lastTestRollbacked = true;
295: // throwan error only in an unknown exception case
296: if (!this .analyseException(e, created)) {
297: throw e;
298: }
299: } finally {
300: this .manager.close();
301: }
302:
303: // now read all the beans
304: try {
305: this .manager = emf.createEntityManager();
306:
307: // now read the beans again from the database
308: for (T toRead : beansCreated) {
309: final T readed = this .manager.find(this .baseClass,
310: this .intro.getPrimaryKey(toRead));
311: beansReaded.add(readed);
312: }
313:
314: // test if the readed collection is equal
315: BeanEqualsTester
316: .testEqualsOnSize(beansCreated, beansReaded);
317: BeanEqualsTester.testEqualsOnPersistentFields(beansCreated,
318: beansReaded, this .intro);
319: BeanEqualsTester.testEqualsImplementationForEntityBeans(
320: beansCreated, beansReaded);
321:
322: } finally {
323: this .manager.close();
324: }
325:
326: }
327:
328: /**
329: * Anylse the exception and react. If the exception is known generate a
330: * assert fail exception
331: *
332: * @param e
333: * the exception
334: * @param lastBean -
335: * last bean or null
336: * @return true if the exception was anylyzed
337: */
338: private boolean analyseException(Exception e, T lastBean) {
339: boolean back = false;
340: if (lastBean != null) {
341: try {
342: StringBuilder sb = new StringBuilder();
343: List<Property> props = this .intro
344: .getPersitentProperties();
345: for (Property prop : props) {
346: sb.append("Field (").append(prop.getName()).append(
347: ") Value: ")
348: .append(prop.getField(lastBean));
349: sb.append("\n");
350: }
351: log.info("Error writing bean: ("
352: + lastBean.getClass().getName() + ")");
353: log.info("Persistent fields values");
354: log.info(sb.toString());
355: log.error("Reason: ", e);
356: } catch (Exception ignore) {
357: log.info("Error writing a bean");
358: }
359: }
360: if (e instanceof GenericJDBCException) {
361: final GenericJDBCException eC = (GenericJDBCException) e;
362: if (eC.getCause() instanceof DataTruncation) {
363: log.info("Some fields in your entity bean class");
364: log.info("are to long (or to short in the database)!");
365: }
366: assertTrue(eC.getLocalizedMessage(), false);
367: back = true;
368: }
369:
370: return back;
371: }
372:
373: }
|