package org.castor.cpa.test.test972;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.cpa.test.framework.CPATestCase;
import org.castor.cpa.test.framework.xml.types.DatabaseEngineType;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.OQLQuery;
import org.exolab.castor.jdo.ObjectNotFoundException;
import org.exolab.castor.jdo.QueryResults;
public final class Test972 extends CPATestCase {
private static final Log LOG = LogFactory.getLog(Test972.class);
private static final String DBNAME = "test972";
private static final String MAPPING = "/org/castor/cpa/test/test972/mapping.xml";
public static Test suite() {
TestSuite suite = new TestSuite(Test972.class.getName());
suite.addTest(new Test972("testLongTransaction"));
suite.addTest(new Test972("testRollback"));
return suite;
}
public Test972(final String name) {
super(name);
}
// Test are only included/excluded for engines that have been tested with this test suite.
public boolean include(final DatabaseEngineType engine) {
return (engine == DatabaseEngineType.DERBY)
|| (engine == DatabaseEngineType.HSQL)
|| (engine == DatabaseEngineType.MYSQL)
|| (engine == DatabaseEngineType.ORACLE)
|| (engine == DatabaseEngineType.POSTGRESQL)
|| (engine == DatabaseEngineType.SAPDB)
|| (engine == DatabaseEngineType.SQL_SERVER);
}
public void testLongTransaction() throws Exception {
Product product = null;
ProductGroup group;
QueryResults results;
Database db = getJDOManager(DBNAME, MAPPING).getDatabase();
db.begin();
LOG.info("Begin transaction to remove Product objects");
// Look up the products and if found delete them from the database
OQLQuery productOql = db.getOQLQuery(
"SELECT p FROM " + Product.class.getName() + " p WHERE p.id = $1");
for (int i = 4; i < 10; ++i) {
productOql.bind(i);
results = productOql.execute();
while (results.hasMore()) {
product = (Product) results.next();
LOG.debug("Deleting existing product: " + product);
db.remove(product);
}
}
LOG.info("End transaction to remove Product objects");
db.commit();
db.begin();
LOG.info("Begin transaction: one-to-one, one-to-many, and dependent relations");
// If no such group exists in the database, create a new object and persist it
OQLQuery groupOql = db.getOQLQuery(
"SELECT g FROM " + ProductGroup.class.getName() + " g WHERE id = $1");
groupOql.bind(3);
results = groupOql.execute();
if (!results.hasMore()) {
group = new ProductGroup();
group.setId(3);
group.setName("a group");
db.create(group);
LOG.debug("Creating new group: " + group);
} else {
group = (ProductGroup) results.next();
LOG.debug("Query result: " + group);
}
// If no such product exists in the database, create a new object and persist it
// Note: product uses group, so group object has to be created first, but can
// be persisted later
productOql.bind(4);
results = productOql.execute();
if (!results.hasMore()) {
product = new Product();
product.setId(4);
product.setName("product4");
product.setPrice(200);
product.setGroup(group);
LOG.debug("Creating new product: " + product);
db.create(product);
} else {
LOG.debug("Query result: " + results.next());
}
LOG.info("End transaction: one-to-one, one-to-many and dependent relations");
db.commit();
db.begin();
LOG.info("Begin transaction: one-to-one and dependent relations");
group = db.load(ProductGroup.class, new Integer(3));
// If no such products with ids 5-8 exist, create new objects and persist them
for (int i = 5; i < 10; ++i) {
int j = i + 1;
productOql.bind(j);
results = productOql.execute();
if (!results.hasMore()) {
product = new Product();
product.setId(i);
product.setName("product" + product.getId());
product.setPrice(300);
product.setGroup(group);
LOG.debug("Creating new product: " + product);
db.create(product);
} else {
LOG.debug("Query result: " + results.next());
}
}
LOG.info("End transaction: one-to-one and dependent relations");
db.commit();
product.setPrice(333);
LOG.info("Updated Product price: " + product);
db.begin();
LOG.info("Begin transaction: long transaction");
// Don't forget to implement TimeStampable for the long transaction!!!
db.update(product);
LOG.info("End transaction: long transaction");
db.commit();
db.close();
LOG.info("Test complete");
}
public void testRollback() throws Exception {
Database db = getJDOManager(DBNAME, MAPPING).getDatabase();
db.begin();
LOG.info("Preparing for rollback bug");
// Prepare the database: add a NewProduct, which references the same
// ProductGroup as most Product objects do
ProductGroup group = db.load(ProductGroup.class, new Integer(3));
NewProduct newProduct = null;
try {
newProduct = db.load(NewProduct.class, new Integer(1));
} catch (ObjectNotFoundException e) {
newProduct = new NewProduct();
newProduct.setId(1);
newProduct.setName("NewProduct1");
newProduct.setPrice(1.0f);
newProduct.setGroup(group);
db.create(newProduct);
LOG.info("NewProduct1 created.");
}
db.commit();
// Now the data are prepared:
// We have Product7 and NewProduct1, both are pointing to Group3
// Below we will load both objects in on transaction and then call rollback
db.begin();
LOG.info("Trying to reproduce rollback bug");
// loading both product entities
newProduct = db.load(NewProduct.class, new Integer(1));
Product product = db.load(Product.class, new Integer(7));
LOG.debug("Product loaded: " + product);
LOG.debug("NewProduct loaded: " + newProduct);
// we only loaded both objects in one tx. Now we are doing a rollback.
LOG.info("Calling Rollback");
db.rollback();
LOG.info("End transaction: Trying to reproduce rollback bug");
db.close();
}
}