blob: 89bcf94345b12d8a8adcf33bb69ebe997d10c959 [file] [log] [blame]
/*
* 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
<<<<<<< Updated upstream
*
* 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
=======
*
* https://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
>>>>>>> Stashed changes
* limitations under the License.
*/
package org.apache.jdo.tck.api.persistencemanager;
import java.util.HashSet;
import java.util.Set;
import javax.jdo.JDOException;
import javax.jdo.JDOHelper;
import javax.jdo.JDOOptimisticVerificationException;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import org.apache.jdo.tck.pc.mylib.VersionedPCPoint;
import org.apache.jdo.tck.util.BatchTestRunner;
/**
* <B>Title:</B> OptimisticFailure <br>
* <B>Keywords:</B> optimistic <br>
* <B>Assertion IDs:</B> A13.5-1 <br>
* <B>Assertion Description: </B> If any instance fails the verification, a
* JDOOptimisticVerificationException is thrown which contains an array of
* JDOOptimisticVerificationException, one for each instance that failed the verification. The
* optimistic transaction is failed, and the transaction is rolled back. The definition of "changed
* instance" is a JDO implementation choice, but it is required that a field that has been changed
* to different values in different transactions results in one of the transactions failing.
*/
public class OptimisticFailure extends PersistenceManagerTest {
/** */
private static final String ASSERTION_FAILED = "Assertion A13.5-1 (OptimisticFailure) failed: ";
/**
* The <code>main</code> is called when the class is directly executed from the command line.
*
* @param args The arguments passed to the program.
*/
public static void main(String[] args) {
BatchTestRunner.run(OptimisticFailure.class);
}
private final VersionedPCPoint p1 =
new VersionedPCPoint(1, 1); // this will be updated in tx1, updated in tx2, verified in tx3
private final VersionedPCPoint p2 =
new VersionedPCPoint(2, 2); // this will be updated in tx1, deleted in tx2, verified in tx3
private final VersionedPCPoint p3 =
new VersionedPCPoint(3, 3); // this will be deleted in tx1, updated in tx2
private final VersionedPCPoint p4 =
new VersionedPCPoint(4, 4); // this will be deleted in tx1, deleted in tx2
private final VersionedPCPoint p5 =
new VersionedPCPoint(5, 5); // this will be unchanged in tx1, updated in tx2, verified in tx3
private Object p1oid = null;
private Object p2oid = null;
private Object p3oid = null;
private Object p4oid = null;
private Object p5oid = null;
/**
* @see org.apache.jdo.tck.JDO_Test#localSetUp()
*/
@Override
protected void localSetUp() {
addTearDownClass(VersionedPCPoint.class);
}
/** */
public void test() {
pm = getPM();
PersistenceManager pm2 = pmf.getPersistenceManager();
PersistenceManager pm3 = pmf.getPersistenceManager();
try {
runTestOptimistic(pm, pm2, pm3);
} finally {
cleanupPM(pm3);
pm3 = null;
cleanupPM(pm2);
pm2 = null;
cleanupPM(pm);
pm = null;
}
}
/** */
private void runTestOptimistic(
PersistenceManager pm1, PersistenceManager pm2, PersistenceManager pm3) {
if (!isOptimisticSupported()) {
if (debug) logger.debug("OptimisticFailure tests not run; Optimistic not supported");
return;
}
Transaction tx1 = pm1.currentTransaction();
Transaction tx2 = pm2.currentTransaction();
Transaction tx3 = pm3.currentTransaction();
try {
tx1.setOptimistic(true);
tx2.setOptimistic(true);
// create five instances to test
tx1.begin();
pm1.makePersistent(p1);
pm1.makePersistent(p2);
pm1.makePersistent(p3);
pm1.makePersistent(p4);
pm1.makePersistent(p5);
p1oid = pm1.getObjectId(p1);
p2oid = pm1.getObjectId(p2);
p3oid = pm1.getObjectId(p3);
p4oid = pm1.getObjectId(p4);
p5oid = pm1.getObjectId(p5);
tx1.commit();
// update/delete the instances in tx1
tx1.begin();
VersionedPCPoint p1tx1 = (VersionedPCPoint) pm1.getObjectById(p1oid, true);
VersionedPCPoint p2tx1 = (VersionedPCPoint) pm1.getObjectById(p2oid, true);
VersionedPCPoint p3tx1 = (VersionedPCPoint) pm1.getObjectById(p3oid, true);
VersionedPCPoint p4tx1 = (VersionedPCPoint) pm1.getObjectById(p4oid, true);
p1tx1.setX(101);
p2tx1.setX(201);
pm1.deletePersistent(p3tx1);
pm1.deletePersistent(p4tx1);
// update/delete the instances in tx2
tx2.begin();
VersionedPCPoint p1tx2 = (VersionedPCPoint) pm2.getObjectById(p1oid, true);
VersionedPCPoint p2tx2 = (VersionedPCPoint) pm2.getObjectById(p2oid, true);
VersionedPCPoint p3tx2 = (VersionedPCPoint) pm2.getObjectById(p3oid, true);
VersionedPCPoint p4tx2 = (VersionedPCPoint) pm2.getObjectById(p4oid, true);
VersionedPCPoint p5tx2 = (VersionedPCPoint) pm2.getObjectById(p5oid, true);
p1tx2.setX(102);
pm2.deletePersistent(p2tx2);
p3tx2.setX(202);
pm2.deletePersistent(p4tx2);
p5tx2.setX(502); // this change must not be committed
Set<VersionedPCPoint> expectedFailedObjects = new HashSet<>();
expectedFailedObjects.add(p1tx2);
expectedFailedObjects.add(p2tx2);
expectedFailedObjects.add(p3tx2);
expectedFailedObjects.add(p4tx2);
// commit tx1 (should succeed)
tx1.commit();
tx1 = null;
// commit tx2 (should fail)
try {
tx2.commit();
fail(ASSERTION_FAILED, "concurrent commit not detected");
} catch (JDOOptimisticVerificationException ex) {
// verify the correct information in the exception
Throwable[] ts = ex.getNestedExceptions();
int length = ts == null ? 0 : ts.length;
int expectedFailures = expectedFailedObjects.size();
if (length != expectedFailures) {
fail(
ASSERTION_FAILED,
"Nested exceptions[] wrong size: expected " + expectedFailures + ", got " + length);
}
for (int i = 0; i < length; ++i) {
Throwable t = ts[i];
if (t instanceof JDOOptimisticVerificationException) {
if (debug) logger.debug("Expected exception caught " + t);
JDOException jex = (JDOException) t;
Object failed = jex.getFailedObject();
if (failed == null) {
fail(ASSERTION_FAILED, "Found unexpected null in failed object");
} else {
if (expectedFailedObjects.remove(failed)) {
if (debug)
logger.debug(
"Found expected failed instance, oid: " + JDOHelper.getObjectId(failed));
} else {
fail(ASSERTION_FAILED, "Unexpected failed instance: " + failed);
}
}
} else {
fail(ASSERTION_FAILED, "Unexpected nested exception: " + t.toString());
}
}
}
tx2 = null;
tx3.begin();
VersionedPCPoint p1tx3 = (VersionedPCPoint) pm3.getObjectById(p1oid, true);
VersionedPCPoint p2tx3 = (VersionedPCPoint) pm3.getObjectById(p2oid, true);
VersionedPCPoint p5tx3 = (VersionedPCPoint) pm3.getObjectById(p5oid, true);
verify(p1tx3, 101);
verify(p2tx3, 201);
verify(p5tx3, 5);
tx3.commit();
tx3 = null;
} finally {
if ((tx3 != null) && tx3.isActive()) tx3.rollback();
if ((tx2 != null) && tx2.isActive()) tx2.rollback();
if ((tx1 != null) && tx1.isActive()) tx1.rollback();
}
}
/**
* @param p PCPoint instance
* @param value value
*/
protected void verify(VersionedPCPoint p, int value) {
if (p.getX() != value) {
fail(
ASSERTION_FAILED,
"VersionedPCPoint has wrong value: expected " + value + ", got " + p.getX());
}
}
}