blob: 4bc5ad982c9a3162490ca63bc4f12dad57772da0 [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 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.jpa.advanced;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.advanced.*;
import org.eclipse.persistence.exceptions.OptimisticLockException;
import junit.framework.Test;
import junit.framework.TestSuite;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.PersistenceException;
/**
* <p>
* <b>Purpose</b>: Test TopLink's EJB 3.0 optimistic concurrency functionality.
* <p>
* <b>Description</b>: This class creates a test suite and adds tests to the
* suite. The database gets initialized prior to the test methods.
* <p>
* <b>Responsibilities</b>:
* <ul>
* <li> Run tests for TopLink's EJB 3.0 optimistic concurrency functionality.
* </ul>
* @see org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator
*/
public class OptimisticConcurrencyJUnitTestSuite extends JUnitTestCase {
public OptimisticConcurrencyJUnitTestSuite() {
super();
}
public OptimisticConcurrencyJUnitTestSuite(String name) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite("Optimistic Concurrency");
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testSetup"));
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testCreateProjects"));
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testCreateEmployeeWithFlush"));
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testVersionUpdateWithCorrectValue"));
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testVersionUpdateWithIncorrectValue"));
suite.addTest(new OptimisticConcurrencyJUnitTestSuite("testVersionUpdateWithNullValue"));
return suite;
}
/**
* The setup is done as a test, both to record its failure, and to allow execution in the server.
*/
public void testSetup() {
new AdvancedTableCreator().replaceTables(JUnitTestCase.getServerSession());
clearCache();
}
/**
* Creates two projects used in later tests.
*/
public void testCreateProjects() {
EntityManager em = createEntityManager();
Project project1, project2;
beginTransaction(em);
project1 = ModelExamples.projectExample1();
project2 = ModelExamples.projectExample2();
em.persist(project1);
em.persist(project2);
commitTransaction(em);
}
/**
* test for issue 635: NullPointerException occuring for Object typed version fields.
* Employee has a write lock (version) field of type Integer
* The NullPointerException is thrown when comparing versions in
* ObjectChangeSet#compareWriteLockValues
*/
public void testCreateEmployeeWithFlush() {
EntityManager em = createEntityManager();
Project project1, project2;
Employee employee;
try {
beginTransaction(em);
employee = ModelExamples.employeeExample1();
em.persist(employee);
// first flush: Employee is written to the database
Query query = em.createNamedQuery("findProjectByName");
query.setParameter("name", "Farmer effecency evaluations");
project1 = (Project) query.getSingleResult();
employee.getProjects().add(project1);
// second flush: Employee is modified, but
// no update to EMPLOYEE table; only join table entry is written
query = em.createNamedQuery("findProjectByName");
query.setParameter("name", "Feline Demographics Assesment");
project2 = (Project) query.getSingleResult();
employee.getProjects().add(project2);
// third flush: Employee is modified, but
// no update to EMPLOYEE table; only join table entry is written
// A NullPointerException in ObjectChangeSet#compareWriteLockValues
commitTransaction(em);
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
}
/**
* test: updating the version field with the in-memory value.
* This should be allowed; there's no change for TopLink to detect this.
*/
public void testVersionUpdateWithCorrectValue() {
EntityManager em = createEntityManager();
Employee employee;
try {
beginTransaction(em);
employee = ModelExamples.employeeExample1();
em.persist(employee);
commitTransaction(em);
beginTransaction(em);
employee.setVersion(1);
commitTransaction(em);
} catch (RuntimeException re) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw re;
}
}
/**
* test: updating the version field with value != in-memory value.
* This should throw an OptimisticLockException
*/
public void testVersionUpdateWithIncorrectValue() {
EntityManager em = createEntityManager();
Employee employee;
try {
beginTransaction(em);
employee = ModelExamples.employeeExample1();
em.persist(employee);
commitTransaction(em);
beginTransaction(em);
Employee employee1 = em.find(Employee.class, employee.getId());
employee1.setVersion(2);
commitTransaction(em);
fail("updating object version with wrong value didn't throw exception");
} catch (PersistenceException pe) {
// expected behavior
} catch (Exception exception) {
Throwable persistenceException = exception;
// Remove an wrapping exceptions such as rollback, runtime, etc.
while (persistenceException != null && !(persistenceException instanceof OptimisticLockException)) {
// In the server this is always a rollback exception, need to get nested exception.
persistenceException = persistenceException.getCause();
}
if (persistenceException instanceof OptimisticLockException) {
OptimisticLockException oe = (OptimisticLockException) persistenceException;
return;
} else {
fail("updating object version with wrong value threw a wrong exception: " + exception.getMessage());
}
} finally {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
}
}
/**
* test: updating the version field with null value.
* This should throw an exception
*/
public void testVersionUpdateWithNullValue() {
EntityManager em = createEntityManager();
Employee employee;
try {
beginTransaction(em);
employee = ModelExamples.employeeExample1();
em.persist(employee);
commitTransaction(em);
beginTransaction(em);
Employee employee2 = em.find(Employee.class, employee.getId());
employee2.setVersion(null);
commitTransaction(em);
fail("employee2.setVersion(null) didn't throw exception");
} catch (PersistenceException pe) {
// expected behavior
} catch (Exception exception) {
Throwable persistenceException = exception;
// Remove an wrapping exceptions such as rollback, runtime, etc.
while (persistenceException != null && !(persistenceException instanceof OptimisticLockException)) {
// In the server this is always a rollback exception, need to get nested exception.
persistenceException = persistenceException.getCause();
}
if (persistenceException instanceof OptimisticLockException) {
OptimisticLockException oe = (OptimisticLockException) persistenceException;
return;
} else {
fail("employee2.setVersion(null) threw a wrong exception: " + exception.getMessage());
}
} finally {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
}
}
}