blob: fe359007471bad20637fb96a284596df8acd6ef2 [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:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.simultaneous;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.queries.DeleteAllQuery;
import org.eclipse.persistence.queries.SQLCall;
import org.eclipse.persistence.sequencing.DefaultSequence;
import org.eclipse.persistence.sequencing.NativeSequence;
import org.eclipse.persistence.sequencing.Sequence;
import org.eclipse.persistence.sequencing.TableSequence;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.testing.framework.TestCase;
import org.eclipse.persistence.testing.framework.TestErrorException;
import org.eclipse.persistence.testing.framework.TestProblemException;
import org.eclipse.persistence.testing.framework.TestWarningException;
import org.eclipse.persistence.testing.models.interfaces.InterfaceHashtableProject;
import org.eclipse.persistence.testing.models.employee.domain.*;
/**
* Tests several scenarios of adding sequences and descriptors, sequence preallocation; inserting objects concurrently.
*/
public class AddDescriptorsMultithreadedTest extends MultithreadTestCase {
protected static boolean allTestsShouldStop;
protected AddDescriptorsMultithreadedTest() {
super();
setDescription("Runs provided tests concurently with adding descriptors.");
}
@Override
protected void setup() {
super.setup();
allTestsShouldStop = false;
}
protected static AddDescriptorsMultithreadedTest createMultithreadedTest(int nAddDescriptorsTests, long timeToSleepBetweenAddingDescriptors, String testName, int nTests, long timeToStopTests) {
AddDescriptorsMultithreadedTest test = new AddDescriptorsMultithreadedTest();
Vector tests = new Vector(nAddDescriptorsTests + nTests);
InterfaceHashtableProject project = new InterfaceHashtableProject();
for (int i=0; i < nAddDescriptorsTests; i++) {
tests.add(new AddDescriptorsTest(i, nAddDescriptorsTests, timeToSleepBetweenAddingDescriptors, project));
}
for (int i=0; i < nTests; i++) {
if (testName.equals("SequencePreallocationTest")) {
tests.add(new SequencePreallocationTest(i));
} else if (testName.equals("InsertTest")) {
tests.add(new InsertTest(i, nTests));
} else {
throw new TestProblemException("Unknown test name: " + testName);
}
}
if (nAddDescriptorsTests == 0 && timeToStopTests > 0) {
tests.add(new Timer(timeToStopTests));
}
test.setTests(tests);
test.generateTestName();
return test;
}
void generateTestName() {
ArrayList<String> testNames = new ArrayList();
HashMap<String, Integer> map = new HashMap();
for (int i=0; i < this.test.length; i++) {
String testName = this.test[i].getName();
if (testNames.contains(testName)) {
int count = map.get(testName);
map.put(testName, count + 1);
} else {
testNames.add(testName);
map.put(testName, 1);
}
}
String name = "";
for(int k=0; k < testNames.size(); k++) {
String testName = testNames.get(k);
if (k > 0) {
name += ";_";
}
name += testName;
int count = map.get(testName);
if (count > 1) {
name += "_" + map.get(testName)+"threads";
}
}
setName(name);
}
/*
* If AddDescriptorsTest not used then use Timer to stop the tests after specified time.
*/
public static class Timer extends TestCase {
Timer(long timeToStopTests) {
this.timeToStopTests = timeToStopTests;
setName("Timer("+timeToStopTests+")");
}
long timeToStopTests;
@Override
public void test() {
try {
Thread.sleep(timeToStopTests);
} catch (InterruptedException ex) {
throw new TestProblemException("Thread.sleep(timeToStopTests) failed ", ex);
}
allTestsShouldStop = true;
}
}
/*
* Adds descriptors, if timeToSleepBetweenAddingDescriptors then sleeps between adding descriptors.
*/
public static class AddDescriptorsTest extends TestCase {
public AddDescriptorsTest(int testNumber, int numberOfTests, long timeToSleepBetweenAddingDescriptors, InterfaceHashtableProject project) {
this.testNumber = testNumber;
this.numberOfTests = numberOfTests;
this.timeToSleepBetweenAddingDescriptors = timeToSleepBetweenAddingDescriptors;
this.project = project;
String name = "AddDescriptorsTest";
if (timeToSleepBetweenAddingDescriptors > 0) {
name += "(" + timeToSleepBetweenAddingDescriptors + ")";
}
setName(name);
}
int testNumber;
int numberOfTests;
long timeToSleepBetweenAddingDescriptors;
InterfaceHashtableProject project;
static int numberOfCompletedTests = 0;
static Object lock = Boolean.TRUE;
@Override
public void test() {
DatabaseSession dbSession;
if (getSession().isDatabaseSession()) {
dbSession = (DatabaseSession)getSession();
} else {
// must be ClientSession
dbSession = (DatabaseSession)(getAbstractSession().getParent());
}
int nSize = project.getOrderedDescriptors().size();
// if numberOfTests = 10 then the first test uses k = 0, 10, 20 etc; the second k = 1, 11, 21 etc.
for (int k = testNumber; k < nSize; k = k + numberOfTests) {
ClassDescriptor descriptor = project.getOrderedDescriptors().get(k);
getAbstractSession().log(SessionLog.FINEST, SessionLog.MISC, "AddDescriptorsTest adding descriptor for class = " + Helper.getShortClassName(descriptor.getJavaClass()), new Object[]{}, null, false);
DatabaseField sequenceNumberField = descriptor.getMappingForAttributeName("id").getField();
descriptor.setSequenceNumberField(sequenceNumberField);
String seqName = "SEQ_" + sequenceNumberField.getTableName();
descriptor.setSequenceNumberName(seqName);
int k3 = k % 3;
// try adding different sequence types
if (k3 == 0) {
dbSession.addSequence(new NativeSequence(seqName));
} else if (k == 1) {
dbSession.addSequence(new TableSequence(seqName));
} else {
// use default sequence - nothing to do
}
// try using both addDescriptor and addDescriptors methods
if (k % 2 == 0) {
dbSession.addDescriptor(descriptor);
} else {
ArrayList descriptors = new ArrayList();
descriptors.add(descriptor);
dbSession.addDescriptors(descriptors);
}
if (timeToSleepBetweenAddingDescriptors > 0) {
try {
Thread.sleep(timeToSleepBetweenAddingDescriptors);
} catch (InterruptedException ex) {
throw new TestProblemException("Thread.sleep(timeToSleepBetweenAddingDescriptors) failed ", ex);
}
}
}
synchronized(lock) {
numberOfCompletedTests++;
if (numberOfCompletedTests == numberOfTests) {
allTestsShouldStop = true;
// get ready for the next run
numberOfCompletedTests = 0;
}
}
}
@Override
protected void verify() {
DatabaseSession dbSession;
if (getSession().isDatabaseSession()) {
dbSession = (DatabaseSession)getSession();
} else {
// must be ClientSession
dbSession = (DatabaseSession)(getAbstractSession().getParent());
}
int nSize = project.getOrderedDescriptors().size();
// if numberOfTests = 10 then the first test uses k = 0, 10, 20 etc; the second k = 1, 11, 21 etc.
for (int k = testNumber; k < nSize; k = k + numberOfTests) {
ClassDescriptor descriptor = project.getOrderedDescriptors().get(k);
descriptor = dbSession.getDescriptor(descriptor.getJavaClass());
if (descriptor == null) {
throw new TestErrorException(descriptor + " is not found in the session");
}
DatabaseField sequenceNumberField = descriptor.getMappingForAttributeName("id").getField();
String seqName = "SEQ_" + sequenceNumberField.getTableName();
Sequence sequence = dbSession.getPlatform().getSequence(seqName);
if (sequence == null) {
throw new TestErrorException("Not found sequence " + seqName + " defined for class " + descriptor.getAlias());
}
int k3 = k % 3;
// try adding different sequence types
if (k3 == 0) {
if (!sequence.isNative()) {
throw new TestErrorException(sequence + " defined for class " + descriptor.getAlias() + " is wrong. NativeSequence was expected");
}
} else if (k == 1) {
if (!sequence.isTable()) {
throw new TestErrorException(sequence + " defined for class " + descriptor.getAlias() + " is wrong. TableSequence was expected");
}
} else {
if (!(sequence instanceof DefaultSequence)) {
throw new TestErrorException(sequence + " defined for class " + descriptor.getAlias() + " is wrong. DefaultSequence was expected");
}
}
}
}
/*
* Concurrently runs nAddDescriptorsTests AddDescriptorsTests.
* If timeToSleepBetweenAddingDescriptors > 0 then each AddDescriptorTest sleeps after adding each descriptor.
*/
public static AddDescriptorsMultithreadedTest createMultithreadedTest(int nAddDescriptorsTests, long timeToSleepBetweenAddingDescriptors) {
return AddDescriptorsMultithreadedTest.createMultithreadedTest(nAddDescriptorsTests, timeToSleepBetweenAddingDescriptors, "", 0, 0);
}
}
/*
* In a loop assigns sequence number for different types
* (which causes sequence number preallocation) then rolls back throwing all the preallocated numbers away.
* Does not have verify method - tests for deadlocks.
* Stops when either AddDescriptorsTest or Timer set allTestsShouldStop flag to false.
*/
public static class SequencePreallocationTest extends TestCase {
public SequencePreallocationTest(int testNumber) {
this.testNumber = testNumber;
setName("SequencePreallocationTest");
}
int testNumber;
@Override
public void test() {
// Test execution causes deadlock on SQL Server
if (getAbstractSession().getParent().getPlatform().isSQLServer()) {
throw new TestWarningException("Not supported on MS SQL Server");
}
int index = 0;
while (!allTestsShouldStop) {
getAbstractSession().beginTransaction();
try {
UnitOfWork uow = getSession().acquireUnitOfWork();
Object obj;
if (index == 0) {
obj = new Address();
index ++;
} else if (index == 1) {
obj = new Employee();
index ++;
} else {
obj = new SmallProject();
index = 0;
}
uow.assignSequenceNumber(obj);
} finally {
getAbstractSession().rollbackTransaction();
}
}
}
/*
* Concurrently runs nAddDescriptorsTests AddDescriptorTests and nTests SequencePreallocationTests.
* If timeToSleepBetweenAddingDescriptors > 0 then each AddDescriptorTest sleep afters adding each descriptor.
*/
public static AddDescriptorsMultithreadedTest createMultithreadedTestWithAddDescriptors(int nAddDescriptorsTests, long timeToSleepBetweenAddingDescriptors, int nTests) {
return AddDescriptorsMultithreadedTest.createMultithreadedTest(nAddDescriptorsTests, timeToSleepBetweenAddingDescriptors, "SequencePreallocationTest", nTests, 0);
}
/*
* Concurrently runs nTests SequencePreallocationTests.
* timeToStopTest > 0 must be specified, or the test will run forever.
*/
public static AddDescriptorsMultithreadedTest createMultithreadedTest(int nTests, long timeToStopTests) {
return AddDescriptorsMultithreadedTest.createMultithreadedTest(0, 0, "SequencePreallocationTest", nTests, timeToStopTests);
}
}
/*
* In a loop inserts objects of different types.
* Stops when either AddDescriptorsTest or Timer set allTestsShouldStop flag to false.
* Does not have verify method - tests for deadlocks.
* The last test to reset deletes all the inserted objects.
*/
public static class InsertTest extends TestCase {
public InsertTest(int testNumber, int numberOfTests) {
this.testNumber = testNumber;
this.numberOfTests = numberOfTests;
setName("InsertTest");
}
int testNumber;
int numberOfTests;
static int numberOfCompletedTests = 0;
static Object lock = Boolean.TRUE;
@Override
public void test() {
// Test execution causes deadlock on SQL Server
if (getAbstractSession().getParent().getPlatform().isSQLServer()) {
throw new TestWarningException("Not supported on MS SQL Server");
}
int index3 = testNumber % 3;
String strTestNumber = Integer.toString(testNumber);
while (!allTestsShouldStop) {
UnitOfWork uow = getSession().acquireUnitOfWork();
Object obj;
if (index3 == 0) {
Address address;
address = new Address();
address.setCity(strTestNumber);
address.setCountry("InsertTest");
obj = address;
index3 = 1;
} else if (index3 == 1) {
Employee emp = new Employee();
emp.setFirstName(strTestNumber);
emp.setLastName("InsertTest");
obj = emp;
index3 = 2;
} else {
SmallProject project = new SmallProject();
project.setName(strTestNumber);
project.setDescription("InsertTest");
obj = project;
index3 = 0;
}
uow.registerObject(obj);
uow.commit();
}
}
@Override
public void reset() {
// the last test deletes the objects created by all tests
synchronized(lock) {
numberOfCompletedTests++;
if (numberOfCompletedTests == numberOfTests) {
Session session = getSession();
if(session.getPlatform().isSymfoware()) {
// Symfoware doesn't support DeleteAllQuery. Therefore call DELETE statements directly instead.
session.executeNonSelectingCall(new SQLCall("DELETE FROM ADDRESS WHERE (COUNTRY = 'InsertTest')"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM SALARY WHERE EXISTS(SELECT t0.EMP_ID FROM EMPLOYEE t0 WHERE (t0.L_NAME = 'InsertTest') AND (t0.EMP_ID = SALARY.EMP_ID))"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM PROJ_EMP WHERE EXISTS(SELECT t0.EMP_ID FROM EMPLOYEE t0 WHERE (t0.L_NAME = 'InsertTest') AND (t0.EMP_ID = PROJ_EMP.EMP_ID))"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM RESPONS WHERE EXISTS(SELECT t0.EMP_ID FROM EMPLOYEE t0 WHERE (t0.L_NAME = 'InsertTest') AND (t0.EMP_ID = RESPONS.EMP_ID))"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM PHONE WHERE EXISTS(SELECT t0.EMP_ID FROM EMPLOYEE t0 WHERE (t0.L_NAME = 'InsertTest') AND (t0.EMP_ID = PHONE.EMP_ID))"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM CHILD WHERE EXISTS(SELECT t0.EMP_ID FROM EMPLOYEE t0 WHERE (t0.L_NAME = 'InsertTest') AND (t0.EMP_ID = CHILD.PARENT_EMP_ID))"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM EMPLOYEE WHERE (L_NAME = 'InsertTest')"));
session.executeNonSelectingCall(new SQLCall("DELETE FROM PROJECT WHERE (DESCRIP = 'InsertTest')"));
} else {
// delete all created objects
UnitOfWork uow = session.acquireUnitOfWork();
DeleteAllQuery deleteAddresses = new DeleteAllQuery(Address.class);
deleteAddresses.setSelectionCriteria(deleteAddresses.getExpressionBuilder().get("country").equal("InsertTest"));
uow.executeQuery(deleteAddresses);
DeleteAllQuery deleteEmployees = new DeleteAllQuery(Employee.class);
deleteEmployees.setSelectionCriteria(deleteEmployees.getExpressionBuilder().get("lastName").equal("InsertTest"));
uow.executeQuery(deleteEmployees);
DeleteAllQuery deleteProjects = new DeleteAllQuery(SmallProject.class);
deleteProjects.setSelectionCriteria(deleteProjects.getExpressionBuilder().get("description").equal("InsertTest"));
uow.executeQuery(deleteProjects);
uow.commit();
}
// get ready for the next run
numberOfCompletedTests = 0;
}
}
}
/*
* Concurrently runs nAddDescriptorsTests AddDescriptorTests and nTests InsertTests.
* If timeToSleepBetweenAddingDescriptors > 0 then each AddDescriptorTest sleep afters adding each descriptor.
*/
public static AddDescriptorsMultithreadedTest createMultithreadedTestWithAddDescriptors(int nAddDescriptorsTests, long timeToSleepBetweenAddingDescriptors, int nTests) {
return AddDescriptorsMultithreadedTest.createMultithreadedTest(nAddDescriptorsTests, timeToSleepBetweenAddingDescriptors, "InsertTest", nTests, 0);
}
/*
* Concurrently runs nTests InsertTests.
* timeToStopTest > 0 must be specified, or the test will run forever.
*/
public static AddDescriptorsMultithreadedTest createMultithreadedTest(int nTests, long timeToStopTests) {
return AddDescriptorsMultithreadedTest.createMultithreadedTest(0, 0, "InsertTest", nTests, timeToStopTests);
}
}
}