| /* |
| * 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); |
| } |
| } |
| } |