| /* |
| * 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.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; |
| import org.apache.openjpa.persistence.kernel.common.apps. |
| ModInstanceCallbackTests; |
| import org.apache.openjpa.persistence.kernel.common.apps.ModRuntimeTest1; |
| |
| public class TestIncrementalFlushes extends BaseKernelTest { |
| |
| public TestIncrementalFlushes(String str) { |
| super(str); |
| } |
| |
| /** |
| * Creates a new instance of TestIncrementalFlushes |
| */ |
| public TestIncrementalFlushes() { |
| } |
| |
| @Override |
| 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()); |
| |
| 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; |
| |
| @Override |
| protected void eventOccurred(TransactionEvent event) { |
| if (event.getType() == TransactionEvent.BEFORE_FLUSH) |
| flushes++; |
| else if (event.getType() == TransactionEvent.BEFORE_COMMIT) |
| commits++; |
| } |
| } |
| } |