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