/* | |
* TestIncrementalFlushes.java | |
* | |
* Created on October 12, 2006, 11:24 AM | |
* | |
* To change this template, choose Tools | Template Manager | |
* and open the template in the editor. | |
*/ | |
/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.openjpa.persistence.kernel; | |
import org.apache.openjpa.persistence.kernel.common.apps.ModInstanceCallbackTests; | |
import org.apache.openjpa.persistence.kernel.common.apps.ModRuntimeTest1; | |
import org.apache.openjpa.event.AbstractTransactionListener; | |
import org.apache.openjpa.event.TransactionEvent; | |
import org.apache.openjpa.kernel.PCState; | |
import org.apache.openjpa.persistence.OpenJPAEntityManager; | |
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; | |
public class TestIncrementalFlushes extends BaseKernelTest { | |
public TestIncrementalFlushes(String str) { | |
super(str); | |
} | |
/** | |
* Creates a new instance of TestIncrementalFlushes | |
*/ | |
public TestIncrementalFlushes() { | |
} | |
public void setUp() { | |
deleteAll(ModRuntimeTest1.class); | |
// deleteAll(ModInstanceCallbackTests.class); | |
} | |
public void testBasicJdoPreStore() { | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
pm.flush(); | |
assertTrue(a.preStoreCalled); | |
endTx(pm); | |
} | |
public void testNoFlush() { | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
endTx(pm); | |
assertTrue(a.preStoreCalled); | |
} | |
public void testFlushNoChange() { | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
pm.flush(); | |
endTx(pm); | |
assertTrue(a.preStoreCalled); | |
assertEquals(10, a.getIntField()); | |
} | |
/** | |
* Helper method for some common test cases. See utilizations of | |
* this below. | |
*/ | |
private void basicHelper(boolean update, boolean multi, boolean dfg, | |
boolean nonDFG) { | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
if (update) { | |
endTx(pm); | |
Object oid = pm.getObjectId(a); | |
endEm(pm); | |
pm = getPM(true, false); | |
startTx(pm); | |
a = (ModInstanceCallbackTests) pm | |
.find(ModInstanceCallbackTests.class, oid); | |
} else { | |
pm.flush(); | |
} | |
if (dfg) | |
a.setIntField(11); | |
if (nonDFG) | |
a.setNonDFGField(11); | |
if (multi) { | |
pm.flush(); | |
if (dfg) | |
a.setIntField(12); | |
if (nonDFG) | |
a.setNonDFGField(12); | |
} | |
endTx(pm); | |
// if no changes were made and we're in update mode, then this | |
// object won't have had jdoPreStore() called. | |
// if (!(update && (!dfg && !nonDFG))) | |
// assertTrue("a.prestoreCalled is false", a.preStoreCalled); | |
if (multi) { | |
if (dfg) | |
assertEquals("a.getIntField is not 12", 12, a.getIntField()); | |
if (nonDFG) | |
assertEquals("a.getNonDFGField is not 12", 12, | |
a.getNonDFGField()); | |
} else { | |
if (dfg) | |
assertEquals("a.getIntField is not 12", 11, a.getIntField()); | |
if (nonDFG) | |
assertEquals("a.getNonDFGField is not 12", 11, | |
a.getNonDFGField()); | |
} | |
} | |
public void testFlushStorePrimaryDFGChange() { | |
basicHelper(false, false, true, false); | |
basicHelper(false, true, true, false); | |
basicHelper(true, false, true, false); | |
basicHelper(true, true, true, false); | |
} | |
public void testFlushStorePrimaryNonDFGChange() { | |
basicHelper(false, false, false, true); | |
basicHelper(false, true, false, true); | |
basicHelper(true, false, false, true); | |
basicHelper(true, true, false, true); | |
} | |
public void testFlushStorePrimaryNonDFGAndDFGChange() { | |
basicHelper(false, false, true, true); | |
basicHelper(false, true, true, true); | |
basicHelper(true, false, true, true); | |
basicHelper(true, true, true, true); | |
} | |
public void testFlushStorePrimaryNoChanges() { | |
basicHelper(false, false, false, false); | |
basicHelper(false, true, false, false); | |
basicHelper(true, false, false, false); | |
basicHelper(true, true, false, false); | |
} | |
public void testJdoPreStoreWithModificationBeforeFlush() { | |
tjpswmHelper(true); | |
} | |
public void testJdoPreStoreWithModificationAfterFlush() { | |
tjpswmHelper(false); | |
} | |
private void tjpswmHelper(boolean before) { | |
// set retainvalues to false so that we can ensure that the | |
// data in the database is correct, and that we're not just | |
// testing that the JVM data is correct. | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
// by setting the name to 'bar', the jdoPreStore() invocation | |
// will set the parent to a new object. This ensures that new | |
// objects created in jdoPreStore() make their way into the DB | |
// during commit. | |
if (before) { | |
a.setStringField("bar"); | |
pm.flush(); | |
} else { | |
pm.flush(); | |
a.setStringField("bar"); | |
} | |
endTx(pm); | |
assertTrue("a.preStoreCalled is false", a.preStoreCalled); | |
assertNotNull("a.getOneOne is null", a.getOneOne()); | |
assertTrue("getOneOne().getstrngfld.equals(jdoPrestore) is false", | |
a.getOneOne().getStringField().equals("jdoPreStore")); | |
} | |
public void testOneToOneBefore() { | |
totoHelper(true, true, false); | |
totoHelper(true, false, false); | |
totoHelper(true, true, true); | |
totoHelper(true, false, true); | |
} | |
public void testOneToOneAfter() { | |
totoHelper(false, true, false); | |
totoHelper(false, false, false); | |
totoHelper(false, true, true); | |
totoHelper(false, false, true); | |
} | |
private void totoHelper(boolean before, boolean persist, | |
boolean multi) { | |
// set retainvalues to false so that we can ensure that the | |
// data in the database is correct, and that we're not just | |
// testing that the JVM data is correct. | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModInstanceCallbackTests a = new ModInstanceCallbackTests("foo", 10); | |
pm.persist(a); | |
ModRuntimeTest1 parent = new ModRuntimeTest1("baz", 11); | |
if (!before) | |
pm.flush(); | |
if (persist) | |
pm.persist(parent); | |
a.setOneOne(parent); | |
if (before) | |
pm.flush(); | |
ModRuntimeTest1 oldParent = null; | |
if (multi) { | |
oldParent = parent; | |
parent = new ModRuntimeTest1("newParent", 12); | |
if (!before) | |
pm.flush(); | |
if (persist) | |
pm.persist(parent); | |
a.setOneOne(parent); | |
if (before) | |
pm.flush(); | |
} | |
endTx(pm); | |
assertTrue("a.preStoreCalled is false", a.preStoreCalled); | |
assertNotNull("a.getOneOne is null", a.getOneOne()); | |
if (!multi) | |
assertTrue("a.getOneOne().getStringField().equals(baz) is false", | |
a.getOneOne().getStringField().equals("baz")); | |
else { | |
assertTrue( | |
"a.getOneOne().getStringField().equals(newParent) is false", | |
a.getOneOne().getStringField().equals("newParent")); | |
// if multi, then we really should delete the baz | |
// parent. This isn't happening right now. | |
// ### should be a bug | |
//assertTrue (JDOHelper.isDeleted (oldParent)); | |
} | |
} | |
private void assertState(Object o, PCState state, OpenJPAEntityManager pm) { | |
assertEquals(state, getStateManager(o, pm).getPCState()); | |
} | |
private void commitAndTestDelete(OpenJPAEntityManager pm, Object o) { | |
Object oid = pm.getObjectId(o); | |
endTx(pm); | |
pm = getPM(); | |
try { | |
pm.find(Object.class, oid); | |
fail("should not be able to load deleted object"); | |
} catch (Exception e) { | |
// expected case | |
} | |
} | |
public void testDeleteNew() { | |
OpenJPAEntityManager pm = getPM(true, false); | |
startTx(pm); | |
ModRuntimeTest1 a = new ModRuntimeTest1("foo", 10); | |
pm.persist(a); | |
pm.remove(a); | |
assertState(a, PCState.PNEWDELETED, pm); | |
} | |
public void testOptimisticLockGivesCorrectError() { | |
OpenJPAEntityManager pm1 = getPM(true, false); | |
OpenJPAEntityManager pm2 = getPM(true, false); | |
ModRuntimeTest1 a1 = new ModRuntimeTest1("foo", 10); | |
startTx(pm1); | |
pm1.persist(a1); | |
endTx(pm1); | |
ModRuntimeTest1 a2 = (ModRuntimeTest1) | |
pm2.find(ModRuntimeTest1.class, pm2.getObjectId(a1)); | |
startTx(pm2); | |
a2.setStringField("foobar"); | |
endTx(pm2); | |
startTx(pm1); | |
a1.setStringField("foobarbaz"); | |
try { | |
endTx(pm1); | |
} catch (Exception ole) { | |
// expected case | |
} finally { | |
rollbackTx(pm1); | |
pm1.close(); | |
pm2.close(); | |
} | |
} | |
/** | |
* Verify that flushes to the datastore are isolated from other | |
* PersistenceManagers. This is mostly a test of the underlying | |
* datastore's transactional isolation capabilities. | |
* <p/> | |
* Disabled: this hangs on Sybase. | |
*/ | |
public void XXXtestFlushesAreIsolated() { | |
final String name = "testFlushesAreIsolated"; | |
deleteAll(ModRuntimeTest1.class); | |
OpenJPAEntityManager flushPM = getPM(true, false); | |
startTx(flushPM); | |
OpenJPAEntityManager readPM = getPM(true, false); | |
startTx(readPM); | |
assertSize(0, flushPM.createNativeQuery("stringField == '" + name + "'", | |
ModRuntimeTest1.class)); | |
assertSize(0, readPM.createNativeQuery("stringField == '" + name + "'", | |
ModRuntimeTest1.class)); | |
ModRuntimeTest1 a = new ModRuntimeTest1(name, randomInt().intValue()); | |
flushPM.persist(a); | |
assertSize(0, readPM.createNativeQuery("name == '" + name + "'", | |
ModRuntimeTest1.class)); | |
flushPM.flush(); | |
// make sure the other pm doesn't see the flushed object | |
assertSize(0, readPM.createNativeQuery("name == '" + name + "'", | |
ModRuntimeTest1.class)); | |
flushPM.remove(a); | |
assertSize(0, flushPM.createNativeQuery("name == '" + name + "'", | |
ModRuntimeTest1.class)); | |
assertSize(0, readPM.createNativeQuery("name == '" + name + "'", | |
ModRuntimeTest1.class)); | |
endTx(flushPM); | |
endEm(flushPM); | |
endTx(readPM); | |
endEm(readPM); | |
} | |
public void testEmptyFlush() { | |
OpenJPAEntityManager pm = getPM(); | |
TListener listener = new TListener(); | |
((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener); | |
startTx(pm); | |
ModRuntimeTest1 pc = new ModRuntimeTest1(); | |
pm.persist(pc); | |
pm.flush(); | |
assertEquals(1, listener.flushes); | |
assertEquals(0, listener.commits); | |
pm.flush(); | |
assertEquals(1, listener.flushes); | |
assertEquals(0, listener.commits); | |
pc.setIntField(3); | |
pm.flush(); | |
assertEquals(2, listener.flushes); | |
assertEquals(0, listener.commits); | |
endTx(pm); | |
assertEquals(2, listener.flushes); | |
assertEquals(1, listener.commits); | |
endEm(pm); | |
} | |
public void testEmptyRollback() { | |
OpenJPAEntityManager pm = getPM(); | |
TListener listener = new TListener(); | |
((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener); | |
startTx(pm); | |
pm.flush(); | |
rollbackTx(pm); | |
assertEquals(0, listener.flushes); | |
assertEquals(0, listener.commits); | |
endEm(pm); | |
} | |
public void testEmptyCommit() { | |
OpenJPAEntityManager pm = getPM(); | |
TListener listener = new TListener(); | |
((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener); | |
startTx(pm); | |
endTx(pm); | |
assertEquals(0, listener.flushes); | |
assertEquals(1, listener.commits); | |
endEm(pm); | |
} | |
private static class TListener | |
extends AbstractTransactionListener { | |
public int flushes = 0; | |
public int commits = 0; | |
protected void eventOccurred(TransactionEvent event) { | |
if (event.getType() == event.BEFORE_FLUSH) | |
flushes++; | |
else if (event.getType() == event.BEFORE_COMMIT) | |
commits++; | |
} | |
} | |
} |