001: /*
002: * TestIncrementalFlushes.java
003: *
004: * Created on October 12, 2006, 11:24 AM
005: *
006: * To change this template, choose Tools | Template Manager
007: * and open the template in the editor.
008: */
009: /*
010: * Licensed to the Apache Software Foundation (ASF) under one
011: * or more contributor license agreements. See the NOTICE file
012: * distributed with this work for additional information
013: * regarding copyright ownership. The ASF licenses this file
014: * to you under the Apache License, Version 2.0 (the
015: * "License"); you may not use this file except in compliance
016: * with the License. You may obtain a copy of the License at
017: *
018: * http://www.apache.org/licenses/LICENSE-2.0
019: *
020: * Unless required by applicable law or agreed to in writing,
021: * software distributed under the License is distributed on an
022: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
023: * KIND, either express or implied. See the License for the
024: * specific language governing permissions and limitations
025: * under the License.
026: */
027: package org.apache.openjpa.persistence.kernel;
028:
029: import org.apache.openjpa.persistence.kernel.common.apps.ModInstanceCallbackTests;
030: import org.apache.openjpa.persistence.kernel.common.apps.ModRuntimeTest1;
031:
032: import org.apache.openjpa.event.AbstractTransactionListener;
033: import org.apache.openjpa.event.TransactionEvent;
034: import org.apache.openjpa.kernel.PCState;
035: import org.apache.openjpa.persistence.OpenJPAEntityManager;
036: import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
037:
038: public class TestIncrementalFlushes extends BaseKernelTest {
039:
040: public TestIncrementalFlushes(String str) {
041: super (str);
042: }
043:
044: /**
045: * Creates a new instance of TestIncrementalFlushes
046: */
047: public TestIncrementalFlushes() {
048: }
049:
050: public void setUp() {
051: deleteAll(ModRuntimeTest1.class);
052: // deleteAll(ModInstanceCallbackTests.class);
053: }
054:
055: public void testBasicJdoPreStore() {
056: OpenJPAEntityManager pm = getPM(true, false);
057: startTx(pm);
058: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
059: "foo", 10);
060: pm.persist(a);
061: pm.flush();
062: assertTrue(a.preStoreCalled);
063: endTx(pm);
064: }
065:
066: public void testNoFlush() {
067: OpenJPAEntityManager pm = getPM(true, false);
068: startTx(pm);
069: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
070: "foo", 10);
071: pm.persist(a);
072: endTx(pm);
073: assertTrue(a.preStoreCalled);
074: }
075:
076: public void testFlushNoChange() {
077: OpenJPAEntityManager pm = getPM(true, false);
078: startTx(pm);
079: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
080: "foo", 10);
081: pm.persist(a);
082: pm.flush();
083: endTx(pm);
084: assertTrue(a.preStoreCalled);
085: assertEquals(10, a.getIntField());
086: }
087:
088: /**
089: * Helper method for some common test cases. See utilizations of
090: * this below.
091: */
092: private void basicHelper(boolean update, boolean multi,
093: boolean dfg, boolean nonDFG) {
094: OpenJPAEntityManager pm = getPM(true, false);
095: startTx(pm);
096:
097: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
098: "foo", 10);
099: pm.persist(a);
100: if (update) {
101: endTx(pm);
102: Object oid = pm.getObjectId(a);
103: endEm(pm);
104: pm = getPM(true, false);
105: startTx(pm);
106: a = (ModInstanceCallbackTests) pm.find(
107: ModInstanceCallbackTests.class, oid);
108: } else {
109: pm.flush();
110: }
111:
112: if (dfg)
113: a.setIntField(11);
114: if (nonDFG)
115: a.setNonDFGField(11);
116:
117: if (multi) {
118: pm.flush();
119:
120: if (dfg)
121: a.setIntField(12);
122: if (nonDFG)
123: a.setNonDFGField(12);
124: }
125:
126: endTx(pm);
127:
128: // if no changes were made and we're in update mode, then this
129: // object won't have had jdoPreStore() called.
130: // if (!(update && (!dfg && !nonDFG)))
131: // assertTrue("a.prestoreCalled is false", a.preStoreCalled);
132:
133: if (multi) {
134: if (dfg)
135: assertEquals("a.getIntField is not 12", 12, a
136: .getIntField());
137: if (nonDFG)
138: assertEquals("a.getNonDFGField is not 12", 12, a
139: .getNonDFGField());
140: } else {
141: if (dfg)
142: assertEquals("a.getIntField is not 12", 11, a
143: .getIntField());
144: if (nonDFG)
145: assertEquals("a.getNonDFGField is not 12", 11, a
146: .getNonDFGField());
147: }
148: }
149:
150: public void testFlushStorePrimaryDFGChange() {
151: basicHelper(false, false, true, false);
152: basicHelper(false, true, true, false);
153: basicHelper(true, false, true, false);
154: basicHelper(true, true, true, false);
155: }
156:
157: public void testFlushStorePrimaryNonDFGChange() {
158: basicHelper(false, false, false, true);
159: basicHelper(false, true, false, true);
160: basicHelper(true, false, false, true);
161: basicHelper(true, true, false, true);
162: }
163:
164: public void testFlushStorePrimaryNonDFGAndDFGChange() {
165: basicHelper(false, false, true, true);
166: basicHelper(false, true, true, true);
167: basicHelper(true, false, true, true);
168: basicHelper(true, true, true, true);
169: }
170:
171: public void testFlushStorePrimaryNoChanges() {
172: basicHelper(false, false, false, false);
173: basicHelper(false, true, false, false);
174: basicHelper(true, false, false, false);
175: basicHelper(true, true, false, false);
176: }
177:
178: public void testJdoPreStoreWithModificationBeforeFlush() {
179: tjpswmHelper(true);
180: }
181:
182: public void testJdoPreStoreWithModificationAfterFlush() {
183: tjpswmHelper(false);
184: }
185:
186: private void tjpswmHelper(boolean before) {
187: // set retainvalues to false so that we can ensure that the
188: // data in the database is correct, and that we're not just
189: // testing that the JVM data is correct.
190: OpenJPAEntityManager pm = getPM(true, false);
191: startTx(pm);
192: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
193: "foo", 10);
194: pm.persist(a);
195:
196: // by setting the name to 'bar', the jdoPreStore() invocation
197: // will set the parent to a new object. This ensures that new
198: // objects created in jdoPreStore() make their way into the DB
199: // during commit.
200: if (before) {
201: a.setStringField("bar");
202: pm.flush();
203: } else {
204: pm.flush();
205: a.setStringField("bar");
206: }
207: endTx(pm);
208: assertTrue("a.preStoreCalled is false", a.preStoreCalled);
209: assertNotNull("a.getOneOne is null", a.getOneOne());
210: assertTrue(
211: "getOneOne().getstrngfld.equals(jdoPrestore) is false",
212: a.getOneOne().getStringField().equals("jdoPreStore"));
213: }
214:
215: public void testOneToOneBefore() {
216: totoHelper(true, true, false);
217: totoHelper(true, false, false);
218: totoHelper(true, true, true);
219: totoHelper(true, false, true);
220: }
221:
222: public void testOneToOneAfter() {
223: totoHelper(false, true, false);
224: totoHelper(false, false, false);
225: totoHelper(false, true, true);
226: totoHelper(false, false, true);
227: }
228:
229: private void totoHelper(boolean before, boolean persist,
230: boolean multi) {
231: // set retainvalues to false so that we can ensure that the
232: // data in the database is correct, and that we're not just
233: // testing that the JVM data is correct.
234: OpenJPAEntityManager pm = getPM(true, false);
235: startTx(pm);
236: ModInstanceCallbackTests a = new ModInstanceCallbackTests(
237: "foo", 10);
238: pm.persist(a);
239:
240: ModRuntimeTest1 parent = new ModRuntimeTest1("baz", 11);
241: if (!before)
242: pm.flush();
243:
244: if (persist)
245: pm.persist(parent);
246:
247: a.setOneOne(parent);
248:
249: if (before)
250: pm.flush();
251:
252: ModRuntimeTest1 oldParent = null;
253: if (multi) {
254: oldParent = parent;
255: parent = new ModRuntimeTest1("newParent", 12);
256:
257: if (!before)
258: pm.flush();
259:
260: if (persist)
261: pm.persist(parent);
262:
263: a.setOneOne(parent);
264:
265: if (before)
266: pm.flush();
267: }
268:
269: endTx(pm);
270: assertTrue("a.preStoreCalled is false", a.preStoreCalled);
271: assertNotNull("a.getOneOne is null", a.getOneOne());
272: if (!multi)
273: assertTrue(
274: "a.getOneOne().getStringField().equals(baz) is false",
275: a.getOneOne().getStringField().equals("baz"));
276: else {
277: assertTrue(
278: "a.getOneOne().getStringField().equals(newParent) is false",
279: a.getOneOne().getStringField().equals("newParent"));
280:
281: // if multi, then we really should delete the baz
282: // parent. This isn't happening right now.
283: // ### should be a bug
284: //assertTrue (JDOHelper.isDeleted (oldParent));
285: }
286: }
287:
288: private void assertState(Object o, PCState state,
289: OpenJPAEntityManager pm) {
290: assertEquals(state, getStateManager(o, pm).getPCState());
291: }
292:
293: private void commitAndTestDelete(OpenJPAEntityManager pm, Object o) {
294: Object oid = pm.getObjectId(o);
295: endTx(pm);
296:
297: pm = getPM();
298: try {
299: pm.find(Object.class, oid);
300: fail("should not be able to load deleted object");
301: } catch (Exception e) {
302: // expected case
303: }
304: }
305:
306: public void testDeleteNew() {
307: OpenJPAEntityManager pm = getPM(true, false);
308: startTx(pm);
309: ModRuntimeTest1 a = new ModRuntimeTest1("foo", 10);
310: pm.persist(a);
311: pm.remove(a);
312: assertState(a, PCState.PNEWDELETED, pm);
313: }
314:
315: public void testOptimisticLockGivesCorrectError() {
316: OpenJPAEntityManager pm1 = getPM(true, false);
317: OpenJPAEntityManager pm2 = getPM(true, false);
318:
319: ModRuntimeTest1 a1 = new ModRuntimeTest1("foo", 10);
320: startTx(pm1);
321: pm1.persist(a1);
322: endTx(pm1);
323:
324: ModRuntimeTest1 a2 = (ModRuntimeTest1) pm2.find(
325: ModRuntimeTest1.class, pm2.getObjectId(a1));
326: startTx(pm2);
327: a2.setStringField("foobar");
328: endTx(pm2);
329:
330: startTx(pm1);
331: a1.setStringField("foobarbaz");
332: try {
333: endTx(pm1);
334: } catch (Exception ole) {
335: // expected case
336: } finally {
337: rollbackTx(pm1);
338:
339: pm1.close();
340: pm2.close();
341: }
342: }
343:
344: /**
345: * Verify that flushes to the datastore are isolated from other
346: * PersistenceManagers. This is mostly a test of the underlying
347: * datastore's transactional isolation capabilities.
348: * <p/>
349: * Disabled: this hangs on Sybase.
350: */
351: public void XXXtestFlushesAreIsolated() {
352: final String name = "testFlushesAreIsolated";
353:
354: deleteAll(ModRuntimeTest1.class);
355:
356: OpenJPAEntityManager flushPM = getPM(true, false);
357: startTx(flushPM);
358:
359: OpenJPAEntityManager readPM = getPM(true, false);
360: startTx(readPM);
361:
362: assertSize(0, flushPM.createNativeQuery("stringField == '"
363: + name + "'", ModRuntimeTest1.class));
364: assertSize(0, readPM.createNativeQuery("stringField == '"
365: + name + "'", ModRuntimeTest1.class));
366:
367: ModRuntimeTest1 a = new ModRuntimeTest1(name, randomInt()
368: .intValue());
369:
370: flushPM.persist(a);
371:
372: assertSize(0, readPM.createNativeQuery(
373: "name == '" + name + "'", ModRuntimeTest1.class));
374:
375: flushPM.flush();
376:
377: // make sure the other pm doesn't see the flushed object
378: assertSize(0, readPM.createNativeQuery(
379: "name == '" + name + "'", ModRuntimeTest1.class));
380:
381: flushPM.remove(a);
382:
383: assertSize(0, flushPM.createNativeQuery("name == '" + name
384: + "'", ModRuntimeTest1.class));
385: assertSize(0, readPM.createNativeQuery(
386: "name == '" + name + "'", ModRuntimeTest1.class));
387:
388: endTx(flushPM);
389: endEm(flushPM);
390:
391: endTx(readPM);
392: endEm(readPM);
393: }
394:
395: public void testEmptyFlush() {
396: OpenJPAEntityManager pm = getPM();
397: TListener listener = new TListener();
398: ((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener);
399: startTx(pm);
400: ModRuntimeTest1 pc = new ModRuntimeTest1();
401: pm.persist(pc);
402: pm.flush();
403: assertEquals(1, listener.flushes);
404: assertEquals(0, listener.commits);
405:
406: pm.flush();
407: assertEquals(1, listener.flushes);
408: assertEquals(0, listener.commits);
409:
410: pc.setIntField(3);
411: pm.flush();
412: assertEquals(2, listener.flushes);
413: assertEquals(0, listener.commits);
414:
415: endTx(pm);
416: assertEquals(2, listener.flushes);
417: assertEquals(1, listener.commits);
418:
419: endEm(pm);
420: }
421:
422: public void testEmptyRollback() {
423: OpenJPAEntityManager pm = getPM();
424: TListener listener = new TListener();
425: ((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener);
426: startTx(pm);
427: pm.flush();
428: rollbackTx(pm);
429: assertEquals(0, listener.flushes);
430: assertEquals(0, listener.commits);
431: endEm(pm);
432: }
433:
434: public void testEmptyCommit() {
435: OpenJPAEntityManager pm = getPM();
436: TListener listener = new TListener();
437: ((OpenJPAEntityManagerSPI) pm).addTransactionListener(listener);
438: startTx(pm);
439: endTx(pm);
440: assertEquals(0, listener.flushes);
441: assertEquals(1, listener.commits);
442: endEm(pm);
443: }
444:
445: private static class TListener extends AbstractTransactionListener {
446:
447: public int flushes = 0;
448: public int commits = 0;
449:
450: protected void eventOccurred(TransactionEvent event) {
451: if (event.getType() == event.BEFORE_FLUSH)
452: flushes++;
453: else if (event.getType() == event.BEFORE_COMMIT)
454: commits++;
455: }
456: }
457: }
|