Add a test of Session.refresh(...) functionality.

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14962 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Brian Stansberry 2008-07-21 20:08:07 +00:00
parent 77f9830c77
commit 9d3d0d691a
5 changed files with 328 additions and 8 deletions

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Brian Stansberry
*/
package org.hibernate.test.cache.jbc2.functional;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.hibernate.test.cache.jbc2.functional.util.IsolatedCacheTestSetup;
/**
* A SessionRefreshTest that uses an OPTIMISTIC cache config.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1 $
*/
public class OptimisticSessionRefreshTest extends PessimisticSessionRefreshTest
{
private static final String CACHE_CONFIG = "optimistic-entity";
/**
* Create a new OptimisticSessionRefreshTest.
*
* @param x
*/
public OptimisticSessionRefreshTest(String x)
{
super(x);
}
public static Test suite() throws Exception {
TestSuite suite = new TestSuite(OptimisticSessionRefreshTest.class);
String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE + ".AccountHolder" };
return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
}
@Override
protected String getEntityCacheConfigName() {
return CACHE_CONFIG;
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Brian Stansberry
*/
package org.hibernate.test.cache.jbc2.functional;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.hibernate.test.cache.jbc2.functional.util.IsolatedCacheTestSetup;
/**
* A PessimisticSessionRefreshTest that uses a REPEATABLE_READ cache config.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1 $
*/
public class PessimisticRepeatableSessionRefreshTest extends PessimisticSessionRefreshTest
{
private static final String CACHE_CONFIG = "pessimistic-entity-repeatable";
/**
* Create a new PessimisticRepeatableSessionRefreshTest.
*
* @param x
*/
public PessimisticRepeatableSessionRefreshTest(String x)
{
super(x);
}
public static Test suite() throws Exception {
TestSuite suite = new TestSuite(PessimisticRepeatableSessionRefreshTest.class);
String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE + ".AccountHolder" };
return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
}
@Override
protected String getEntityCacheConfigName() {
return CACHE_CONFIG;
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Brian Stansberry
*/
package org.hibernate.test.cache.jbc2.functional;
import javax.transaction.TransactionManager;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.hibernate.SessionFactory;
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.test.cache.jbc2.functional.classloader.Account;
import org.hibernate.test.cache.jbc2.functional.classloader.ClassLoaderTestDAO;
import org.hibernate.test.cache.jbc2.functional.util.DualNodeJtaTransactionManagerImpl;
import org.hibernate.test.cache.jbc2.functional.util.DualNodeTestUtil;
import org.hibernate.test.cache.jbc2.functional.util.IsolatedCacheTestSetup;
import org.hibernate.test.cache.jbc2.functional.util.TestCacheInstanceManager;
import org.hibernate.test.cache.jbc2.functional.util.TestJBossCacheRegionFactory;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A test that a Session.refresh(...) operation works properly when the
* item being refreshed is in the 2nd level cache.
*
* Uses the infrastructure of our dual-node tests, but
* {@link #configureSecondNode(Configuration)} plays a trick and disables
* the 2nd level cache on the second node. We then use that second node
* to simulate an external process that changes the DB while bypassing the
* cache.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1 $
*/
public class PessimisticSessionRefreshTest extends DualNodeTestCaseBase
{
public static final String OUR_PACKAGE = PessimisticSessionRefreshTest.class.getPackage().getName();
private static final String CACHE_CONFIG = "pessimistic-entity";
protected final Logger log = LoggerFactory.getLogger(getClass());
static int test = 0;
private Cache localCache;
/**
* Create a new PessimisticSessionRefreshTest.
*
* @param x
*/
public PessimisticSessionRefreshTest(String x)
{
super(x);
}
public static Test suite() throws Exception {
TestSuite suite = new TestSuite(PessimisticSessionRefreshTest.class);
String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE + ".AccountHolder" };
return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
}
// --------------------------------------------------------------- Overrides
/**
* Disables use of the second level cache for this session factory.
*
* {@inheritDoc}
*/
@Override
protected void configureSecondNode(Configuration cfg)
{
super.configureSecondNode(cfg);
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
}
@Override
protected void configureCacheFactory(Configuration cfg)
{
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP,
getEntityCacheConfigName());
}
@Override
protected Class getCacheRegionFactory()
{
return TestJBossCacheRegionFactory.class;
}
@Override
protected boolean getUseQueryCache()
{
return false;
}
protected String getEntityCacheConfigName() {
return CACHE_CONFIG;
}
@Override
public String[] getMappings()
{
return new String[] { "cache/jbc2/functional/classloader/Account.hbm.xml" };
}
@Override
protected void cleanupTransactionManagement() {
// Don't clean up the managers, just the transactions
// Managers are still needed by the long-lived caches
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
}
// ------------------------------------------------------------------ Tests
public void testRefreshAfterExternalChange() throws Exception
{
// First session factory uses a cache
CacheManager localManager = TestCacheInstanceManager.getTestCacheManager(DualNodeTestUtil.LOCAL);
this.localCache = localManager.getCache(getEntityCacheConfigName(), true);
TransactionManager localTM = localCache.getConfiguration().getRuntimeConfig().getTransactionManager();
SessionFactory localFactory = getEnvironment().getSessionFactory();
// Second session factory doesn't; just needs a transaction manager
TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestUtil.REMOTE);
SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO(localFactory, localTM);
ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO(remoteFactory, remoteTM);
Integer id = new Integer(1);
dao0.createAccount(dao0.getSmith(), id, new Integer(5), DualNodeTestUtil.LOCAL);
// Basic sanity check
Account acct1 = dao1.getAccount(id);
assertNotNull(acct1);
assertEquals(DualNodeTestUtil.LOCAL, acct1.getBranch());
// This dao's session factory isn't caching, so cache won't see this change
dao1.updateAccountBranch(id, DualNodeTestUtil.REMOTE);
// dao1's session doesn't touch the cache,
// so reading from dao0 should show a stale value from the cache
// (we check to confirm the cache is used)
Account acct0 = dao0.getAccount(id);
assertNotNull(acct0);
assertEquals(DualNodeTestUtil.LOCAL, acct0.getBranch());
// Now call session.refresh and confirm we get the correct value
acct0 = dao0.getAccountWithRefresh(id);
assertNotNull(acct0);
assertEquals(DualNodeTestUtil.REMOTE, acct0.getBranch());
// Double check with a brand new session, in case the other session
// for some reason bypassed the 2nd level cache
ClassLoaderTestDAO dao0A = new ClassLoaderTestDAO(localFactory, localTM);
Account acct0A = dao0A.getAccount(id);
assertNotNull(acct0A);
assertEquals(DualNodeTestUtil.REMOTE, acct0A.getBranch());
}
}

View File

@ -163,6 +163,42 @@ public class ClassLoaderTestDAO
log.debug("Created account " + id);
}
public Account getAccount(Integer id) throws Exception
{
log.debug("Getting account " + id);
tm.begin();
try {
Session session = sessionFactory.getCurrentSession();
Account acct = (Account) session.get(acctClass, id);
tm.commit();
return acct;
}
catch (Exception e) {
log.error("rolling back", e);
tm.rollback();
throw e;
}
}
public Account getAccountWithRefresh(Integer id) throws Exception
{
log.debug("Getting account " + id + " with refresh");
tm.begin();
try {
Session session = sessionFactory.getCurrentSession();
Account acct = (Account) session.get(acctClass, id);
session.refresh(acct);
acct = (Account) session.get(acctClass, id);
tm.commit();
return acct;
}
catch (Exception e) {
log.error("rolling back", e);
tm.rollback();
throw e;
}
}
public void updateAccountBalance(Integer id, Integer newBalance) throws Exception
{
log.debug("Updating account " + id + " to balance " + newBalance);

View File

@ -50,14 +50,7 @@
Hibernate will plug in its own transaction manager integration.
-->
<!--
Node isolation level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<attribute name="IsolationLevel">REPEATABLE_READ</attribute>
<attribute name="IsolationLevel">READ_COMMITTED</attribute>
<!--
Valid modes are LOCAL