blob: ef086d326dfc871e1c61a50fcc7d8c96b24a7006 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.unitofwork;
import java.util.Vector;
import org.eclipse.persistence.exceptions.QueryException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.testing.framework.TestErrorException;
import org.eclipse.persistence.testing.models.employee.domain.Employee;
import org.eclipse.persistence.testing.models.employee.domain.PhoneNumber;
/**
* Test that exceptions are thrown when attempts to conform query results in a unit of work fail.
* References: CR 2188.
*
* Description:
* The test generally involves two classes, the second having a
* pointer to the first. In this case PhoneNumber has an Employee
* owner, and Contact has a MailAddress instance.
* In a Unit of Work, an object of the first class is modified, or has
* one of its field's changed. Then a query is executed on the second
* class (i.e PhoneNumber), which is conditional on the fields of its
* instance of the first class.
* The changes and queries are coordinated so that the former should alter
* the outcome of the latter.
* If Toplink is unable to conform the results of the query with the
* original change, a warning exception should be thrown.
*/
public class UnitOfWorkConformExceptionTest extends org.eclipse.persistence.testing.framework.AutoVerifyTestCase {
protected Employee bob;
protected UnitOfWork uow;
boolean pass;
ReadObjectQuery phoneNumberQuery;
ReadAllQuery phoneNumbersQuery;
ReadAllQuery contactsQuery;
public UnitOfWorkConformExceptionTest() {
setDescription("Test that exceptions are thrown when attempts to conform query results in a unit of work fail.");
}
@Override
public void setup() {
getAbstractSession().beginTransaction();
phoneNumberQuery = new ReadObjectQuery();
phoneNumbersQuery = new ReadAllQuery();
phoneNumberQuery.setReferenceClass(PhoneNumber.class);
phoneNumbersQuery.setReferenceClass(PhoneNumber.class);
Expression exp = new ExpressionBuilder().get("owner").get("firstName").equal("Bob");
phoneNumberQuery.setSelectionCriteria(exp);
phoneNumbersQuery.setSelectionCriteria(exp);
phoneNumberQuery.conformResultsInUnitOfWork();
phoneNumbersQuery.conformResultsInUnitOfWork();
contactsQuery = new ReadAllQuery();
contactsQuery.setReferenceClass(Contact.class);
exp = new ExpressionBuilder().get("mailAddress").get("mailAddress").like("t%");
contactsQuery.setSelectionCriteria(exp);
contactsQuery.conformResultsInUnitOfWork();
}
@Override
public void reset() {
getAbstractSession().rollbackTransaction();
getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
}
@Override
public void test() {
testThrowNoConformException();
testThrowConformExceptionWithIndirection();
testThrowConformExceptionInAllCases();
}
protected void setupTrial(int value) {
pass = false;
uow = getSession().acquireUnitOfWork();
uow.setShouldThrowConformExceptions(value);
}
protected void tearDownTrial() {
uow.release();
}
protected void testThrowNoConformException() {
// First test the default behavior.
setupTrial(UnitOfWorkImpl.DO_NOT_THROW_CONFORM_EXCEPTIONS);
changeBobToFred();
try {
String owner = getAPhoneNumberOfBob().getOwner().getFirstName();
if (owner.equals("Fred")) {
// The default behavior should be like this.
} else {
throw new TestErrorException("The first name was not conformed to UOW changes: " + owner);
}
} catch (Exception e) {
throw new TestErrorException("An exception should not be thrown in the default case: " + e);
} finally {
tearDownTrial();
}
}
protected void testThrowConformExceptionWithIndirection() {
// First test that an exception is thrown with indirection and an update.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
changeBobToFred();
try {
getAPhoneNumberOfBob();
} catch (QueryException e) {
// This is the excpected behavior.
pass = true;
} finally {
tearDownTrial();
}
if (!pass) {
throw new TestErrorException("A conforming query exception should have been thrown in update case.");
}
// Second test that an exception is thrown with indirection and a deletion.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
deleteBob();
try {
getAPhoneNumberOfBob();
} catch (QueryException e) {
// This is the expected behavior.
pass = true;
} finally {
tearDownTrial();
}
if (!pass) {
throw new TestErrorException("A conforming query exception should have been thrown in delete case.");
}
// Third test that an exception is thrown with indirection and an insertion.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
addPhoneNumberToBob();
try {
getAPhoneNumberOfBob();
} catch (QueryException e) {
// This is the expected behavior.
pass = true;
} finally {
tearDownTrial();
}
if (!pass) {
throw new TestErrorException("A conforming query exception should be thrown in insertion case.");
}
// Fourth test that an exception is thrown for a readObjectQuery with Indirection.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
changeBobToFred();
try {
getASinglePhoneNumberOfBob();
} catch (QueryException e) {
// This is the excpected behavior.
pass = true;
} finally {
tearDownTrial();
}
if (!pass) {
throw new TestErrorException("A conforming query exception should have been thrown in read single object case.");
}
// Fifth test that an exception is not thrown when indirection is not used.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
changeAMailAddress();
try {
getContacts();
} catch (QueryException e) {
throw new TestErrorException("A conforming query exception should not have be thrown when indirection not used.");
} finally {
tearDownTrial();
}
}
protected void testThrowConformExceptionInAllCases() {
// First test that an exception is thrown with an update.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
changeBobToFred();
try {
getAPhoneNumberOfBob();
} catch (QueryException e) {
// This is the excpected behavior.
pass = true;
} finally {
tearDownTrial();
}
if (!pass) {
throw new TestErrorException("A conforming query exception should have been thrown with an update.");
}
// Second test that an exception is thrown even in a case without indirection.
setupTrial(UnitOfWorkImpl.THROW_ALL_CONFORM_EXCEPTIONS);
changeAMailAddress();
try {
Vector v = getContacts();
String s = "";
if (v.size() > 0) {
Contact contact = (Contact)v.firstElement();
s = contact.getMailAddress().mailAddress;
}
throw new TestErrorException("A conforming query exception should have been thrown even when indirection not involved: " +
s + v.size());
} catch (QueryException e) {
// This is the expected behavior.
} finally {
tearDownTrial();
}
}
private void changeBobToFred() {
Expression exp = new ExpressionBuilder().get("firstName").equal("Bob");
bob = (Employee)uow.readObject(Employee.class, exp);
bob.setFirstName("Fred");
}
private void deleteBob() {
Expression exp = new ExpressionBuilder().get("firstName").equal("Bob");
bob = (Employee)uow.readObject(Employee.class, exp);
uow.deleteObject(bob);
}
private void addPhoneNumberToBob() throws QueryException {
PhoneNumber phoneNumber = (PhoneNumber)uow.newInstance(PhoneNumber.class);
bob.addPhoneNumber(phoneNumber);
phoneNumber.setOwner(bob);
}
private PhoneNumber getAPhoneNumberOfBob() throws QueryException {
Vector phoneNumbers = (Vector)uow.executeQuery(phoneNumbersQuery);
return (PhoneNumber)phoneNumbers.firstElement();
}
private PhoneNumber getASinglePhoneNumberOfBob() throws QueryException {
return (PhoneNumber)uow.executeQuery(phoneNumberQuery);
}
private void changeAMailAddress() {
Expression exp = new ExpressionBuilder().get("mailAddress").equal("three@object.com");
MailAddress mailAddress = (MailAddress)uow.readObject(MailAddress.class, exp);
mailAddress.mailAddress = new String("four@object.com");
}
private Vector getContacts() throws QueryException {
return (Vector)uow.executeQuery(contactsQuery);
}
}