blob: e104ae3e5ad4cfdf114dc756faeb6845f6ee106b [file] [log] [blame]
/*
* Copyright (c) 2011, 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:
// 2010-10-27 - James Sutherland (Oracle) initial impl
package org.eclipse.persistence.testing.tests.jpa.partitioned;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import jakarta.persistence.*;
import junit.framework.*;
import org.eclipse.persistence.config.ExclusiveConnectionMode;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.descriptors.partitioning.CustomPartitioningPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.descriptors.partitioning.RangePartitioningPolicy;
import org.eclipse.persistence.descriptors.partitioning.RoundRobinPartitioningPolicy;
import org.eclipse.persistence.descriptors.partitioning.UnionPartitioningPolicy;
import org.eclipse.persistence.descriptors.partitioning.ValuePartitioningPolicy;
import org.eclipse.persistence.mappings.CollectionMapping;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCaseHelper;
import org.eclipse.persistence.testing.models.jpa.partitioned.*;
import org.eclipse.persistence.tools.schemaframework.PopulationManager;
public class PartitionedTestSuite extends JUnitTestCase {
public static boolean validDatabase = true;
public static boolean isRAC = false;
public static Test suite() {
TestSuite suite = new TestSuite("PartitioningTests");
suite.addTest(new PartitionedTestSuite("testSetup"));
suite.addTest(new PartitionedTestSuite("testReadEmployee"));
suite.addTest(new PartitionedTestSuite("testReadAllEmployee"));
suite.addTest(new PartitionedTestSuite("testPersistEmployee"));
suite.addTest(new PartitionedTestSuite("testRemoveEmployee"));
suite.addTest(new PartitionedTestSuite("testUpdateEmployee"));
suite.addTest(new PartitionedTestSuite("testReadProject"));
suite.addTest(new PartitionedTestSuite("testReadAllProject"));
suite.addTest(new PartitionedTestSuite("testPersistProject"));
suite.addTest(new PartitionedTestSuite("testRemoveProject"));
suite.addTest(new PartitionedTestSuite("testUpdateProject"));
suite.addTest(new PartitionedTestSuite("testPartitioning"));
suite.addTest(new PartitionedTestSuite("testPersistPartitioning"));
suite.addTest(new PartitionedTestSuite("testPersistOfficeWithLongName"));
return suite;
}
public PartitionedTestSuite(String name) {
super(name);
}
/**
* Return the name of the persistence context this test uses.
* This allow a subclass test to set this only in one place.
*/
@Override
public String getPersistenceUnitName() {
return "partitioned";
}
/**
* The setup is done as a test, both to record its failure, and to allow execution in the server.
*/
public void testSetup() {
Map properties = new HashMap(JUnitTestCaseHelper.getDatabaseProperties());
if (getServerSession().getPlatform().isDerby()) {
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_MIN,
"2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:derby:node2;create=true");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:derby:node3;create=true");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_MAX,
"8");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_FAILOVER,
"node2, node1");
} else if (getServerSession().getPlatform().isH2()) {
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_MIN,
"2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:h2:test2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:h2:test3");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_MAX,
"8");
} else if (getServerSession().getPlatform().isHSQL()) {
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_MIN,
"2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:hsqldb:file:test2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_URL,
"jdbc:hsqldb:file:test3");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_MAX,
"8");
} else if (!isOnServer() && getServerSession().getPlatform().isOracle() && (getServerSession().getLogin().getURL().indexOf("ems56442") != -1)) {
isRAC = true;
// RAC testing (direct node).
String url = getServerSession().getLogin().getURL();
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_MIN,
"2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_URL,
(url.substring(0, url.length() - 1)) + "3");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_URL,
url);
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_MAX,
"8");
} else if (!isOnServer() && getServerSession().getPlatform().isOracle() && (getServerSession().getLogin().getURL().indexOf("@(DESCRIPTION") != -1)) {
isRAC = true;
// UCP RAC callback testing.
properties.put(
PersistenceUnitProperties.PARTITIONING_CALLBACK,
"org.eclipse.persistence.platform.database.oracle.ucp.UCPDataPartitioningCallback");
} else if (isOnServer()) {
isRAC = true;
try {
Class.forName("weblogic.jdbc.common.internal.DataSourceManager");
} catch (Exception notWebLogic) {
warning("Partitioning tests only run on WebLogic with GridLink.");
return;
}
} else {
// Do not run on Sybase as may hang.
if (getServerSession().getPlatform().isSybase()) {
validDatabase = false;
return;
}
isRAC = true;
// Simulate a RAC using multiple connection pools to the same database.
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_MIN,
"2");
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node2." + PersistenceUnitProperties.CONNECTION_POOL_URL,
getServerSession().getLogin().getURL());
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_URL,
getServerSession().getLogin().getURL());
properties.put(
PersistenceUnitProperties.CONNECTION_POOL + "node3." + PersistenceUnitProperties.CONNECTION_POOL_MAX,
"8");
}
getEntityManagerFactory(getPersistenceUnitName(), properties);
if (isRAC) {
// Disable replication and unioning in RAC.
for (PartitioningPolicy policy : getDatabaseSession().getProject().getPartitioningPolicies().values()) {
if (policy instanceof RoundRobinPartitioningPolicy) {
((RoundRobinPartitioningPolicy)policy).setReplicateWrites(false);
} else if (policy instanceof UnionPartitioningPolicy) {
((UnionPartitioningPolicy)policy).setReplicateWrites(false);
} else if (policy instanceof CustomPartitioningPolicy) {
((EmployeePartitioningPolicy)((CustomPartitioningPolicy)policy).getPolicy()).setReplicate(false);
} else if (policy instanceof RangePartitioningPolicy) {
((RangePartitioningPolicy)policy).setUnionUnpartitionableQueries(false);
} else if (policy instanceof ValuePartitioningPolicy) {
((ValuePartitioningPolicy)policy).setUnionUnpartitionableQueries(false);
}
}
CollectionMapping mapping = (CollectionMapping)getDatabaseSession().getDescriptor(Employee.class).getMappingForAttributeName("projects");
PartitioningPolicy policy = getDatabaseSession().getProject().getPartitioningPolicy("defaut");
mapping.setPartitioningPolicy(policy);
mapping.getSelectionQuery().setPartitioningPolicy(policy);
mapping = (CollectionMapping)getDatabaseSession().getDescriptor(Employee.class).getMappingForAttributeName("managedEmployees");
mapping.setPartitioningPolicy(policy);
mapping.getSelectionQuery().setPartitioningPolicy(policy);
}
new PartitionedTableCreator().replaceTables(getDatabaseSession());
EntityManager em = createEntityManager();
try {
PopulationManager.resetDefaultManager();
beginTransaction(em);
new EmployeePopulator().persistExample(em);
commitTransaction(em);
} finally {
closeEntityManagerAndTransaction(em);
}
clearCache();
}
/**
* Test reading.
*/
public void testReadEmployee() {
if (!validDatabase) {
return;
}
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Query query = em.createQuery("Select e from Employee e where e.firstName = :name");
query.setParameter("name", "Bob");
Employee employee = (Employee)query.getSingleResult();
for (int index = 0; index < 3; index++) {
if (!((Employee)query.getSingleResult()).getFirstName().equals("Bob")) {
fail("Employee not correct.");
}
}
commitTransaction(em);
closeEntityManager(em);
for (int index = 0; index < 3; index++) {
clearCache();
em = createEntityManager();
if (!(em.find(Employee.class, employee.pk())).getFirstName().equals("Bob")) {
fail("Employee not correct.");
}
closeEntityManager(em);
}
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
verifyObject(new EmployeePopulator().employeeExample1());
verifyObject(new EmployeePopulator().employeeExample2());
verifyObject(new EmployeePopulator().employeeExample3());
}
/**
* Test reading.
*/
public void testReadProject() {
if (!validDatabase) {
return;
}
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Query query = em.createQuery("Select p from Project p where p.name = :name");
query.setParameter("name", "Sales Reporting");
Project project = (Project)query.getSingleResult();
for (int index = 0; index < 3; index++) {
if (!((Project)query.getSingleResult()).getName().equals("Sales Reporting")) {
fail("Project not correct.");
}
}
commitTransaction(em);
closeEntityManager(em);
for (int index = 0; index < 3; index++) {
clearCache();
em = createEntityManager();
if (!(em.find(Project.class, project.getId())).getName().equals("Sales Reporting")) {
fail("Project not correct.");
}
closeEntityManager(em);
}
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
verifyObject(new EmployeePopulator().largeProjectExample1());
verifyObject(new EmployeePopulator().largeProjectExample2());
verifyObject(new EmployeePopulator().smallProjectExample1());
}
/**
* Test reading.
*/
public void testReadAllEmployee() {
if (!validDatabase) {
return;
}
EntityManager em = createEntityManager();
try {
beginTransaction(em);
int size = em.createQuery("Select e from Employee e").getResultList().size();
for (int index = 0; index < 3; index++) {
if (size != em.createQuery("Select e from Employee e").getResultList().size()) {
fail("Query result size does not match.");
}
}
commitTransaction(em);
closeEntityManager(em);
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
}
/**
* Test reading.
*/
public void testReadAllProject() {
if (!validDatabase) {
return;
}
EntityManager em = createEntityManager();
try {
beginTransaction(em);
int size = em.createQuery("Select p from Project p").getResultList().size();
for (int index = 0; index < 3; index++) {
if (size != em.createQuery("Select p from Project p").getResultList().size()) {
fail("Query result size does not match.");
}
}
commitTransaction(em);
closeEntityManager(em);
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
}
/**
* Test remove.
*/
public void testRemoveEmployee() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
verifyPersistAndRemove(new EmployeePopulator().basicEmployeeExample1());
}
}
/**
* Test remove.
*/
public void testRemoveProject() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
verifyPersistAndRemove(new EmployeePopulator().basicLargeProjectExample2());
}
}
/**
* Test persist.
*/
public void testPersistEmployee() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
verifyPersist(new EmployeePopulator().basicEmployeeExample2());
}
}
/**
* Test persist an Office with a long name to produce a potential negative hashcode.
* Bug 371514 - fragile hashing in HashPartitioningPolicy
*/
public void testPersistOfficeWithLongName() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 25; index++) {
String longName = "Office with a very, very, very long name indeed";
longName += String.valueOf(UUID.randomUUID());
verifyPersist(new Office(longName, index + 1));
}
}
/**
* Test persist.
*/
public void testPersistProject() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
verifyPersist(new EmployeePopulator().basicLargeProjectExample1());
verifyPersist(new EmployeePopulator().basicSmallProjectExample3());
}
}
/**
* Test update.
*/
public void testUpdateEmployee() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
List<Employee> employees = em.createQuery("Select e from Employee e").getResultList();
for (Employee employee : employees) {
employee.setLastName(employee.getLastName() + "2");
employee.addResponsibility("new" + index);
employee.getAddress().setStreet(employee.getAddress().getStreet() + "2");
}
commitTransaction(em);
for (Employee employee : employees) {
verifyObject(employee);
verifyObject(employee.getAddress());
}
clearCache();
for (Employee employee : employees) {
verifyObject(employee);
verifyObject(employee.getAddress());
}
closeEntityManager(em);
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
}
}
/**
* Test update.
*/
public void testUpdateProject() {
if (!validDatabase) {
return;
}
for (int index = 0; index < 3; index++) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
List<Project> projects = em.createQuery("Select p from Project p").getResultList();
for (Project project : projects) {
project.setDescription(project.getDescription() + "2");
}
commitTransaction(em);
for (Project project : projects) {
verifyObject(project);
}
clearCache();
for (Project project : projects) {
verifyObject(project);
}
closeEntityManager(em);
} catch (RuntimeException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
throw e;
}
}
}
/**
* Test that partitioning is being used.
*/
public void testPartitioning() throws Exception {
if (!validDatabase) {
return;
}
boolean found = false;
EntityManager em = createEntityManager();
try {
Project project = (Project)em.createQuery("Select p from Project p").getResultList().get(0);
for (int index = 0; index < 3; index++) {
beginTransaction(em);
Query query = em.createNativeQuery("Select * from PART_PROJECT where PROJ_ID = ?");
query.setParameter(1, project.getId());
List results = query.getResultList();
if (!results.isEmpty()) {
if (found && !isRAC) {
fail("Data found in more than one partition.");
}
found = true;
} else if (isRAC) {
fail("Data not found in all partitions.");
}
commitTransaction(em);
}
if (!found) {
fail("Data not found in any partition.");
}
} catch (Exception e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
throw e;
} finally {
closeEntityManager(em);
}
}
/**
* Test exclusive partitioning with persist.
* The persist should decide the connection, not the query.
*/
public void testPersistPartitioning() throws Exception {
if (!validDatabase) {
return;
}
if (isOnServer()) {
return;
}
for (int count = 0; count < 2; count++) {
Map properties = new HashMap();
properties.put(PersistenceUnitProperties.EXCLUSIVE_CONNECTION_MODE, ExclusiveConnectionMode.Always);
EntityManager em = createEntityManager(properties);
try {
beginTransaction(em);
Employee employee1 = new Employee();
employee1.setLocation("Ottawa");
em.persist(employee1);
commitTransaction(em);
closeEntityManager(em);
clearCache();
em = createEntityManager(properties);
beginTransaction(em);
Employee employee2 = new Employee();
employee2.setLocation("Ottawa");
em.persist(employee2);
Employee result = em.find(Employee.class, new EmployeePK(employee1.getId(), "Toronto"));
if (result != null) {
fail("Employee should not exist.");
}
result = em.find(Employee.class, new EmployeePK(employee1.getId(), "Ottawa"));
rollbackTransaction(em);
if (result == null) {
// Retry once, as sequence select could use wrong node.
if (count == 1) {
fail("Employee not found, wrong partition used.");
}
} else {
return;
}
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
}