| /* |
| * Copyright (c) 1998, 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: |
| // 05/05/2009 Andrei Ilitchev |
| // - JPA 2.0 - OrderedList support. |
| package org.eclipse.persistence.testing.tests.orderedlist; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Vector; |
| |
| import org.eclipse.persistence.annotations.OrderCorrectionType; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.descriptors.changetracking.AttributeChangeTrackingPolicy; |
| import org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy; |
| import org.eclipse.persistence.descriptors.changetracking.ObjectChangeTrackingPolicy; |
| import org.eclipse.persistence.exceptions.QueryException; |
| import org.eclipse.persistence.expressions.Expression; |
| import org.eclipse.persistence.expressions.ExpressionBuilder; |
| import org.eclipse.persistence.indirection.IndirectList; |
| import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform; |
| import org.eclipse.persistence.internal.queries.OrderedListContainerPolicy; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.mappings.CollectionMapping; |
| import org.eclipse.persistence.queries.DataReadQuery; |
| import org.eclipse.persistence.queries.ReadAllQuery; |
| import org.eclipse.persistence.queries.ReadObjectQuery; |
| import org.eclipse.persistence.queries.ReadQuery; |
| import org.eclipse.persistence.queries.ReportQuery; |
| import org.eclipse.persistence.queries.ReportQueryResult; |
| 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.TestModel; |
| import org.eclipse.persistence.testing.models.orderedlist.*; |
| import org.eclipse.persistence.testing.models.orderedlist.EmployeeSystem.ChangeTracking; |
| import org.eclipse.persistence.testing.models.orderedlist.EmployeeSystem.JoinFetchOrBatchRead; |
| |
| import org.eclipse.persistence.testing.framework.TestProblemException; |
| |
| public class OrderListTestModel extends TestModel { |
| /* |
| * Indicates whether to run configuration that don't use listOrderField (useListOrderField==false). |
| * By default is set to false. |
| * Set it to true for debugging: |
| * if something fails with listOrderField (useListOrderField==true) see if it also fails without it. |
| */ |
| static boolean shouldRunWithoutListOrderField = false; |
| |
| /* |
| * There is a single top level model (contained in TestRunModel) that contains multiple models. |
| */ |
| boolean isTopLevel; |
| |
| /* |
| * Top level model loops through all possible combinations of the attributes below and decides whether the combination should run. |
| * Foe each combination of values that should run a model is created and added to the top level model. |
| */ |
| boolean useListOrderField; |
| boolean isPrivatelyOwned; |
| boolean useIndirection; |
| boolean useSecondaryTable; |
| boolean useVarcharOrder; |
| ChangeTracking changeTracking; |
| OrderCorrectionType orderCorrectionType; |
| boolean shouldOverrideContainerPolicy; |
| JoinFetchOrBatchRead joinFetchOrBatchRead; |
| |
| /* |
| * Variables below used by setup / reset: |
| * setup saves there the original state of something, sets a new state required for testing, |
| * then reset brings back the saved original state. |
| */ |
| Map<Class, ObjectChangeTrackingPolicy> originalChangeTrackingPolicies; |
| |
| /* |
| * Constants used by WhereToAdd tests. |
| */ |
| static final String front = "front"; |
| static final String middle = "middle"; |
| static final String end = "end"; |
| |
| /** |
| * Return the JUnit suite to allow JUnit runner to find it. |
| * Unfortunately JUnit only allows suite methods to be static, |
| * so it is not possible to generically do this. |
| */ |
| public static junit.framework.TestSuite suite() { |
| return new OrderListTestModel(); |
| } |
| |
| public OrderListTestModel() { |
| setDescription("This model tests ordered list."); |
| isTopLevel = true; |
| } |
| |
| void addTestModel(DatabasePlatform platform) { |
| if (shouldAddModel(platform)) { |
| addTest(new OrderListTestModel(useListOrderField, useIndirection, isPrivatelyOwned, useSecondaryTable, useVarcharOrder, changeTracking, orderCorrectionType, shouldOverrideContainerPolicy, joinFetchOrBatchRead)); |
| } |
| } |
| |
| /* |
| * Loops through all possible model configurations and adds those for which shouldAddModel returns true. |
| */ |
| void addModels() { |
| DatabasePlatform platform = getSession().getPlatform(); |
| changeTracking = ChangeTracking.ATTRIBUTE; |
| orderCorrectionType = OrderCorrectionType.READ_WRITE; |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.NONE; |
| useVarcharOrder = false; |
| useSecondaryTable = false; |
| isPrivatelyOwned = false; |
| useIndirection = true; |
| useListOrderField = true; |
| shouldOverrideContainerPolicy = false; |
| useVarcharOrder = true; |
| addTestModel(platform); |
| useVarcharOrder = false; |
| useSecondaryTable = true; |
| addTestModel(platform); |
| useSecondaryTable = false; |
| useIndirection = false; |
| changeTracking = ChangeTracking.DEFERRED; |
| addTestModel(platform); |
| changeTracking = ChangeTracking.ATTRIBUTE; |
| useIndirection = true; |
| shouldOverrideContainerPolicy = true; |
| addTestModel(platform); |
| shouldOverrideContainerPolicy = false; |
| for (int i=0; i < ChangeTracking.values().length; i++) { |
| changeTracking = ChangeTracking.values()[i]; |
| addTestModel(platform); |
| } |
| isPrivatelyOwned = true; |
| for (int i=0; i < ChangeTracking.values().length; i++) { |
| changeTracking = ChangeTracking.values()[i]; |
| addTestModel(platform); |
| } |
| changeTracking = ChangeTracking.ATTRIBUTE; |
| isPrivatelyOwned = false; |
| for (int j=0; j < OrderCorrectionType.values().length; j++) { |
| orderCorrectionType = OrderCorrectionType.values()[j]; |
| addTestModel(platform); |
| } |
| orderCorrectionType = OrderCorrectionType.READ_WRITE; |
| for (int k=0; k < JoinFetchOrBatchRead.values().length; k++) { |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.values()[k]; |
| addTestModel(platform); |
| } |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.NONE; |
| useSecondaryTable = true; |
| for (int k=0; k < JoinFetchOrBatchRead.values().length; k++) { |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.values()[k]; |
| addTestModel(platform); |
| } |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.NONE; |
| useSecondaryTable = false; |
| /** Un-comment to run 2^6 * 3 * 6 * 15 tests... (a lot...) |
| do { |
| do { |
| do { |
| do { |
| do { |
| for(int i=0; i < ChangeTracking.values().length; i++) { |
| changeTracking = ChangeTracking.values()[i]; |
| for(int j=0; j < OrderCorrectionType.values().length; j++) { |
| orderCorrectionType = OrderCorrectionType.values()[j]; |
| do{ |
| for(int k=0; k < JoinFetchOrBatchRead.values().length; k++) { |
| joinFetchOrBatchRead = JoinFetchOrBatchRead.values()[k]; |
| addTestModel(platform); |
| } |
| shouldOverrideContainerPolicy = !shouldOverrideContainerPolicy; |
| } while(shouldOverrideContainerPolicy); |
| } |
| } |
| useVarcharOrder = !useVarcharOrder; |
| } while(useVarcharOrder); |
| useSecondaryTable = !useSecondaryTable; |
| } while(useSecondaryTable); |
| isPrivatelyOwned = !isPrivatelyOwned; |
| } while(isPrivatelyOwned); |
| useIndirection = !useIndirection; |
| } while(useIndirection); |
| useListOrderField = !useListOrderField; |
| } while(useListOrderField);*/ |
| } |
| |
| /* |
| * Verifies whether the current model configuration should be added. |
| * Cuts the models with invalid configurations, configurations that don't make any difference. |
| */ |
| boolean shouldAddModel(DatabasePlatform platform) { |
| // listOrderField is not used |
| if(!useListOrderField) { |
| // explicitly asked not to run the model that don't use listOrderField. |
| if(!shouldRunWithoutListOrderField) { |
| return false; |
| } |
| // the model would be identical to OrderCorrectionType.READ |
| if(orderCorrectionType != OrderCorrectionType.READ) { |
| return false; |
| } |
| // the model would be identical to useVarcharOrder==false |
| if(useVarcharOrder) { |
| return false; |
| } |
| } |
| |
| // H2 has an issue with large outer joins, causes null-pointer in driver. |
| // |
| // There is an Eclipselink bug: when using old Oracle-style (+) outer joins the inner joins between |
| // primary and secondary tables substituted by outer joins (employee outer join manager causes manager's salary to outer join to manager). |
| // If there happens to be another outer join to the secondary table (in useSecondaryTable case manager_id is in salary table) |
| // then suddenly the secondary table auto joined to two tables - that causes exception: |
| // ORA-01417: a table may be outer joined to at most one other table. |
| // Now by default Oracle joins in FROM clause, TimesTen can't, therefore TimesTen can't run this model. |
| // |
| if (useSecondaryTable && (joinFetchOrBatchRead == JoinFetchOrBatchRead.OUTER_JOIN)) { |
| if (platform.isH2() || platform.isHSQL() || platform.isTimesTen()) { |
| return false; |
| } |
| } |
| if (useVarcharOrder && !platform.supportsAutoConversionToNumericForArithmeticOperations()) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| public OrderListTestModel(boolean useListOrderField, boolean useIndirection, boolean isPrivatelyOwned, boolean useSecondaryTable, boolean useVarcharOrder, ChangeTracking changeTracking, OrderCorrectionType orderCorrectionType, boolean shouldOverrideContainerPolicy, JoinFetchOrBatchRead joinFetchOrBatchRead) { |
| this.useListOrderField = useListOrderField; |
| this.useIndirection = useIndirection; |
| this.isPrivatelyOwned = isPrivatelyOwned; |
| this.useSecondaryTable = useSecondaryTable; |
| this.useVarcharOrder = useVarcharOrder; |
| this.changeTracking = changeTracking; |
| this.orderCorrectionType = orderCorrectionType; |
| this.shouldOverrideContainerPolicy = shouldOverrideContainerPolicy; |
| this.joinFetchOrBatchRead = joinFetchOrBatchRead; |
| |
| setDescription("This model tests ordered list"); |
| |
| setName(""); |
| addToName(useListOrderField ? "" : "NO_ORDER_LIST"); |
| addToName(useIndirection ? "" : "NO_INDIRECTION"); |
| addToName(isPrivatelyOwned ? "PRIVATE" : ""); |
| addToName(useSecondaryTable ? "SECONDARY_TABLE" : ""); |
| addToName(useVarcharOrder ? "VARCHAR_ORDER" : ""); |
| addToName(changeTracking.toString()); |
| addToName(orderCorrectionType == OrderCorrectionType.READ ? "" : orderCorrectionType.toString()); |
| addToName(shouldOverrideContainerPolicy ? "OVERRIDE_CONTAINER_POLICY" : ""); |
| addToName(joinFetchOrBatchRead.toString()); |
| } |
| |
| void addToName(String strToAdd) { |
| if(strToAdd.length() > 0) { |
| setName(getName() + " " + strToAdd); |
| } |
| } |
| |
| @Override |
| public void addRequiredSystems() { |
| if(!isTopLevel) { |
| addRequiredSystem(new EmployeeSystem(useListOrderField, useIndirection, isPrivatelyOwned, useSecondaryTable, useVarcharOrder, changeTracking, orderCorrectionType, shouldOverrideContainerPolicy, joinFetchOrBatchRead)); |
| } |
| } |
| |
| @Override |
| public void addTests() { |
| if(!isTopLevel) { |
| addTest(new CreateTest()); |
| addTest(new SimpleAddRemoveTest()); |
| // takes too long with joins |
| if(joinFetchOrBatchRead != JoinFetchOrBatchRead.INNER_JOIN && joinFetchOrBatchRead != JoinFetchOrBatchRead.OUTER_JOIN) { |
| addTest(new SimpleAddRemoveTest2()); |
| } |
| // can't run with inner joins because the test sets useResponsibilities and usePhones to false and these lists are empty. |
| if(joinFetchOrBatchRead != JoinFetchOrBatchRead.INNER_JOIN) { |
| addTest(new AddRemoveUpdateTest()); |
| } |
| addTest(new VerifyForeignKeyOfRemovedObject(false)); |
| addTest(new VerifyForeignKeyOfRemovedObject(true)); |
| addTest(new SimpleSetTest()); |
| addTest(new SimpleSetListTest()); |
| addTest(new SimpleSetListTest(false)); |
| addTest(new SimpleSetListTest(true)); |
| addTest(new TranspositionTest(new int[]{0, 1}, new int[]{1, 0}, false)); |
| addTest(new TranspositionTest(new int[]{0, 1}, new int[]{1, 0}, true)); |
| addTest(new TranspositionMergeTest(new int[]{0, 1}, new int[]{1, 0})); |
| addTest(new TranspositionTest(new int[]{1, 3, 5}, new int[]{5, 1, 3}, false)); |
| addTest(new TranspositionTest(new int[]{1, 3, 5}, new int[]{5, 1, 3}, true)); |
| addTest(new TranspositionMergeTest(new int[]{1, 3, 5}, new int[]{5, 1, 3})); |
| // currently only DirectCollectionMapping supports nulls. |
| // bug 278126: Aggregate and Direct collections containing nulls read incorrectly if join is used. |
| // When the bug is fixed the tests should work and condition should be removed. |
| // The bug is partially fixed - the only case result is wrong for DirectCollectionMapping |
| // is a collection that has a single element - null. That collection is read in as empty. |
| addTest(new AddNullTest(front)); |
| addTest(new AddNullTest(middle)); |
| addTest(new AddNullTest(end)); |
| // currently only DirectCollectionMapping supports duplicates. |
| // Duplication doesn't work with joining because of SELECT DISTINCT (would work without DISTINCT). |
| // Should DISTINCT be there? |
| if(joinFetchOrBatchRead != JoinFetchOrBatchRead.INNER_JOIN && joinFetchOrBatchRead != JoinFetchOrBatchRead.OUTER_JOIN) { |
| addTest(new AddDuplicateTest(front)); |
| addTest(new AddDuplicateTest(middle)); |
| addTest(new AddDuplicateTest(end)); |
| } |
| if(joinFetchOrBatchRead == JoinFetchOrBatchRead.OUTER_JOIN) { |
| addTest(new CreateEmptyTest()); |
| addTest(new CreateEmptyManagersTest()); |
| } |
| if(this.useListOrderField) { |
| addTest(new SimpleIndexTest(true)); |
| if(this.shouldOverrideContainerPolicy) { |
| addTest(new VerifyContainerPolicyClassTest()); |
| } |
| if(orderCorrectionType == OrderCorrectionType.EXCEPTION) { |
| if(joinFetchOrBatchRead != JoinFetchOrBatchRead.INNER_JOIN) { |
| addTest(new BreakOrderExceptionTest_OneToMany()); |
| } |
| addTest(new BreakOrderExceptionTest_UnidirectionalOneToMany()); |
| addTest(new BreakOrderExceptionTest_ManyToMany()); |
| addTest(new BreakOrderExceptionTest_DirectCollection()); |
| if(this.changeTracking == ChangeTracking.DEFERRED) { |
| addTest(new BreakOrderExceptionTest_AggregateCollection()); |
| } |
| } else if(orderCorrectionType == OrderCorrectionType.READ_WRITE) { |
| addTest(new BreakOrderCorrectionAndRemoveTest(false)); |
| addTest(new BreakOrderCorrectionAndRemoveTest(true)); |
| addTest(new BreakOrderCorrectionTest(false)); |
| addTest(new BreakOrderCorrectionTest(true)); |
| } |
| } |
| |
| addTest(new CreateManagersTest()); |
| } else { |
| addModels(); |
| } |
| } |
| |
| @Override |
| public void setup() { |
| if(!isTopLevel) { |
| if(changeTracking == ChangeTracking.ATTRIBUTE) { |
| // Save change policies for the all employee demo class in order to restore them at reset time. |
| Map<Class, ObjectChangePolicy> originalChangeTrackingPolicies = new HashMap<>(); |
| |
| originalChangeTrackingPolicies.put(Employee.class, getSession().getDescriptor(Employee.class).getObjectChangePolicy()); |
| getSession().getDescriptor(Employee.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy()); |
| |
| originalChangeTrackingPolicies.put(Project.class, getSession().getDescriptor(Project.class).getObjectChangePolicy()); |
| getSession().getDescriptor(Project.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy()); |
| |
| originalChangeTrackingPolicies.put(SmallProject.class, getSession().getDescriptor(SmallProject.class).getObjectChangePolicy()); |
| getSession().getDescriptor(SmallProject.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy()); |
| |
| originalChangeTrackingPolicies.put(LargeProject.class, getSession().getDescriptor(LargeProject.class).getObjectChangePolicy()); |
| getSession().getDescriptor(LargeProject.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy()); |
| |
| // currently attribute change tracking is incompatible with AggregateCollectionMapping |
| if(this.changeTracking != ChangeTracking.ATTRIBUTE) { |
| originalChangeTrackingPolicies.put(PhoneNumber.class, getSession().getDescriptor(PhoneNumber.class).getObjectChangePolicy()); |
| getSession().getDescriptor(PhoneNumber.class).setObjectChangePolicy(new AttributeChangeTrackingPolicy()); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void reset() { |
| if(!isTopLevel) { |
| // restore original change policies. |
| if(originalChangeTrackingPolicies != null) { |
| Iterator<Map.Entry<Class, ObjectChangeTrackingPolicy>> it = originalChangeTrackingPolicies.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry<Class, ObjectChangeTrackingPolicy> entry = it.next(); |
| getSession().getDescriptor(entry.getKey()).setObjectChangePolicy(entry.getValue()); |
| } |
| originalChangeTrackingPolicies = null; |
| } |
| } |
| } |
| |
| /* |
| * Defines operations on Lists that consist of (in that order): |
| * Employees (for empManager.managerEmployees); |
| * Children (for empManager.children); |
| * Projects (for empManager.projects); |
| * Strings (for empManager.responsibilitiesList); |
| * PhoneNumbers (for empManager.phoneNumbers). |
| * That allows to easily create tests that test all mappings using list order field: |
| * OneToMany, UnidirectionalOneToMany, ManyToMany, DirectCollection, AggregateCollection. |
| * |
| * Note that (for debugging purposes) some of these mappings could be "switched off" by setting the corresponding "use..." flag to false. |
| * Don't do that in INNER_JOIN case - or no objects will be ever read back from db. |
| */ |
| class BaseTest extends TestCase { |
| boolean useManagedEmployees; |
| boolean useChildren; |
| boolean useProjects; |
| boolean useResponsibilities; |
| boolean usePhones; |
| |
| String errorMsg; |
| |
| BaseTest() { |
| this.useManagedEmployees = true; |
| this.useChildren = true; |
| this.useProjects = true; |
| this.useResponsibilities = true; |
| this.usePhones = true; |
| setValidFlags(); |
| |
| errorMsg = ""; |
| |
| setName(getShortClassName()); |
| } |
| |
| /* |
| * Sets some of useManagedEmployees, useChildren, useProjects, useResponsibilities, usePhones to false |
| * as required by the flags copied from OrderListTestModel.this. |
| * If changing this method change validateFlags method accordingly. |
| */ |
| protected void setValidFlags() { |
| // currently attribute change tracking is incompatible with AggregateCollectionMapping |
| if(OrderListTestModel.this.changeTracking == ChangeTracking.ATTRIBUTE) { |
| usePhones = false; |
| } |
| // managedEmployees have nothing: no managedEmployees, no children, no projects, no responsibilities, no phones - |
| // can't read them using INNER_JOIN |
| if(OrderListTestModel.this.joinFetchOrBatchRead == JoinFetchOrBatchRead.INNER_JOIN) { |
| useManagedEmployees = false; |
| } |
| } |
| /* |
| * Validate useManagedEmployees, useChildren, useProjects, useResponsibilities, usePhones flags |
| * so their value don't contradict the flags copied from OrderListTestModel.this. |
| * If changing this method change setValidFlags method accordingly. |
| */ |
| protected void validateFlags() { |
| // currently attribute change tracking is incompatible with AggregateCollectionMapping |
| if(OrderListTestModel.this.changeTracking == ChangeTracking.ATTRIBUTE) { |
| if(usePhones) { |
| errorMsg += "ChangeTracking.ATTRIBUTE requires usePhones==false; "; |
| } |
| } |
| // managedEmployees have nothing: no managedEmployees, no children, no projects, no responsibilities, no phones - |
| // can't read them using INNER_JOIN |
| if(OrderListTestModel.this.joinFetchOrBatchRead == JoinFetchOrBatchRead.INNER_JOIN) { |
| if(useManagedEmployees) { |
| errorMsg += "JoinFetchOrBatchRead.INNER_JOIN requires useManagedEmployees==false; "; |
| } |
| } |
| if(errorMsg.length() > 0) { |
| throw new TestProblemException(errorMsg); |
| } |
| } |
| |
| /* |
| * Debugging: putting a breakpoint at the first line of this method is a good place to set some of |
| * useManagedEmployees, useChildren, useProjects, useResponsibilities, usePhones to false if desired. |
| */ |
| @Override |
| public void setup() { |
| if(!useManagedEmployees && !useChildren && !useProjects && !useResponsibilities && !usePhones) { |
| throw new TestProblemException("useManagedEmployees, useChildren, useProjects, useResponsibilities, usePhones are all false - nothing to test"); |
| } |
| validateFlags(); |
| } |
| |
| @Override |
| public void reset() { |
| if(useManagedEmployees) { |
| if(useSecondaryTable) { |
| getSession().executeNonSelectingSQL("UPDATE OL_SALARY SET MANAGER_ID = NULL"); |
| } else { |
| getSession().executeNonSelectingSQL("UPDATE OL_EMPLOYEE SET MANAGER_ID = NULL"); |
| } |
| } |
| if(useChildren) { |
| getSession().executeNonSelectingSQL("DELETE FROM OL_ALLOWANCE"); |
| getSession().executeNonSelectingSQL("DELETE FROM OL_CHILD"); |
| } |
| if(useProjects) { |
| getSession().executeNonSelectingSQL("DELETE FROM OL_PROJ_EMP"); |
| getSession().executeNonSelectingSQL("DELETE FROM OL_LPROJECT"); |
| getSession().executeNonSelectingSQL("DELETE FROM OL_PROJECT"); |
| } |
| if(useResponsibilities) { |
| getSession().executeNonSelectingSQL("DELETE FROM OL_RESPONS"); |
| } |
| if(usePhones) { |
| getSession().executeNonSelectingSQL("DELETE FROM OL_PHONE"); |
| } |
| |
| getSession().executeNonSelectingSQL("DELETE FROM OL_SALARY"); |
| getSession().executeNonSelectingSQL("DELETE FROM OL_EMPLOYEE"); |
| |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| |
| errorMsg = ""; |
| } |
| |
| /* |
| * Creates a list of objects that could be added to manager: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * Note that indexForName here is used as part of a state of the object being created - not as its position in any list. |
| */ |
| List create(String prefix, int indexForName) { |
| List list = new ArrayList(); |
| String iString = Integer.toString(indexForName); |
| String str = prefix + iString; |
| if(useManagedEmployees) { |
| list.add(new Employee(iString, prefix)); |
| } |
| if(useChildren) { |
| list.add(new Child(iString, prefix)); |
| } |
| if(useProjects) { |
| if(indexForName % 2 == 0) { |
| list.add(new SmallProject(str)); |
| } else { |
| list.add(new LargeProject(str)); |
| } |
| } |
| if(useResponsibilities) { |
| list.add(str); |
| } |
| if(usePhones) { |
| if(prefix.length() > 3) { |
| prefix = prefix.substring(0, 3); |
| } |
| list.add(new PhoneNumber(prefix, iString)); |
| } |
| return list; |
| } |
| |
| /* |
| * Creates a list of nulls that could be added to manager: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List createNull() { |
| List list = new ArrayList(); |
| if(useManagedEmployees) { |
| list.add(null); |
| } |
| if(useChildren) { |
| list.add(null); |
| } |
| if(useProjects) { |
| list.add(null); |
| } |
| if(useResponsibilities) { |
| list.add(null); |
| } |
| if(usePhones) { |
| list.add(null); |
| } |
| return list; |
| } |
| |
| /* |
| * Adds a list of objects to empManager: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * The list should be obtained from getFrom, create, removeFrom or setInto methods. |
| */ |
| void addTo(Employee empManager, List list) { |
| int i = 0; |
| if(useManagedEmployees) { |
| empManager.addManagedEmployee((Employee)list.get(i++)); |
| } |
| if(useChildren) { |
| empManager.getChildren().add(list.get(i++)); |
| } |
| if(useProjects) { |
| empManager.addProject((Project)list.get(i++)); |
| } |
| if(useResponsibilities) { |
| empManager.addResponsibility((String)list.get(i++)); |
| } |
| if(usePhones) { |
| empManager.addPhoneNumber((PhoneNumber)list.get(i++)); |
| } |
| } |
| |
| /* |
| * Adds a list of objects to empManager at index: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * The list should be obtained from getFrom, create, removeFrom or setInto methods. |
| */ |
| void addTo(Employee empManager, int index, List list) { |
| int i = 0; |
| if(useManagedEmployees) { |
| empManager.addManagedEmployee(index, (Employee)list.get(i++)); |
| } |
| if(useChildren) { |
| empManager.getChildren().add(index, list.get(i++)); |
| } |
| if(useProjects) { |
| empManager.addProject(index, (Project)list.get(i++)); |
| } |
| if(useResponsibilities) { |
| empManager.addResponsibility(index, (String)list.get(i++)); |
| } |
| if(usePhones) { |
| empManager.addPhoneNumber(index, (PhoneNumber)list.get(i++)); |
| } |
| } |
| |
| /* |
| * Adds a list of objects to empManager at index: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * The list should be obtained from getFrom, create, removeFrom or setInto methods. |
| */ |
| void addTo_NoRelMaintanence(Employee empManager, int index, List list) { |
| int i = 0; |
| if(useManagedEmployees) { |
| empManager.getManagedEmployees().add(index, (Employee)list.get(i++)); |
| } |
| if(useChildren) { |
| empManager.getChildren().add(index, list.get(i++)); |
| } |
| if(useProjects) { |
| empManager.getProjects().add(index, (Project)list.get(i++)); |
| } |
| if(useResponsibilities) { |
| empManager.addResponsibility(index, (String)list.get(i++)); |
| } |
| if(usePhones) { |
| empManager.addPhoneNumber(index, (PhoneNumber)list.get(i++)); |
| } |
| } |
| |
| /* |
| * Removes a list of objects from empManager at index. |
| * Returns list of removed objects: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List removeFrom(Employee empManager, int index) { |
| List list = new ArrayList(); |
| if(useManagedEmployees) { |
| list.add(empManager.removeManagedEmployee(index)); |
| } |
| if(useChildren) { |
| list.add(empManager.getChildren().remove(index)); |
| } |
| if(useProjects) { |
| list.add(empManager.removeProject(index)); |
| } |
| if(useResponsibilities) { |
| list.add(empManager.removeResponsibility(index)); |
| } |
| if(usePhones) { |
| list.add(empManager.removePhoneNumber(index)); |
| } |
| return list; |
| } |
| |
| /* |
| * Removes a list of objects from empManager at index. |
| * Returns list of removed objects: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List removeFrom_NoRelMaintanence(Employee empManager, int index) { |
| List list = new ArrayList(); |
| if(useManagedEmployees) { |
| list.add(empManager.getManagedEmployees().remove(index)); |
| } |
| if(useChildren) { |
| list.add(empManager.getChildren().remove(index)); |
| } |
| if(useProjects) { |
| list.add(empManager.getProjects().remove(index)); |
| } |
| if(useResponsibilities) { |
| list.add(empManager.removeResponsibility(index)); |
| } |
| if(usePhones) { |
| list.add(empManager.removePhoneNumber(index)); |
| } |
| return list; |
| } |
| |
| /* |
| * Gets a list of objects from empManager at index: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List getFrom(Employee empManager, int index) { |
| List list = new ArrayList(); |
| if(useManagedEmployees) { |
| list.add(empManager.getManagedEmployees().get(index)); |
| } |
| if(useChildren) { |
| list.add(empManager.getChildren().get(index)); |
| } |
| if(useProjects) { |
| list.add(empManager.getProjects().get(index)); |
| } |
| if(useResponsibilities) { |
| list.add(empManager.getResponsibilitiesList().get(index)); |
| } |
| if(usePhones) { |
| list.add(empManager.getPhoneNumbers().get(index)); |
| } |
| return list; |
| } |
| |
| /* |
| * Sets a list of objects into empManager at index. |
| * Returns list of removed objects: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List setInto(Employee empManager, int index, List list) { |
| int i = 0; |
| List listOut = new ArrayList(); |
| if(useManagedEmployees) { |
| listOut.add(empManager.setManagedEmployee(index, (Employee)list.get(i++))); |
| } |
| if(useChildren) { |
| listOut.add(empManager.getChildren().set(index, list.get(i++))); |
| } |
| if(useProjects) { |
| listOut.add(empManager.setProject(index, (Project)list.get(i++))); |
| } |
| if(useResponsibilities) { |
| listOut.add(empManager.setResponsibility(index, (String)list.get(i++))); |
| } |
| if(usePhones) { |
| listOut.add(empManager.setPhoneNumber(index, (PhoneNumber)list.get(i++))); |
| } |
| return listOut; |
| } |
| |
| /* |
| * Sets a list of objects into empManager at index. |
| * Returns list of removed objects: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| */ |
| List setInto_NoRelMaintanence(Employee empManager, int index, List list) { |
| int i = 0; |
| List listOut = new ArrayList(); |
| if(useManagedEmployees) { |
| listOut.add(empManager.getManagedEmployees().set(index, (Employee)list.get(i++))); |
| } |
| if(useChildren) { |
| listOut.add(empManager.getChildren().set(index, list.get(i++))); |
| } |
| if(useProjects) { |
| listOut.add(empManager.getProjects().set(index, (Project)list.get(i++))); |
| } |
| if(useResponsibilities) { |
| listOut.add(empManager.setResponsibility(index, (String)list.get(i++))); |
| } |
| if(usePhones) { |
| listOut.add(empManager.setPhoneNumber(index, (PhoneNumber)list.get(i++))); |
| } |
| return listOut; |
| } |
| |
| /* |
| * Sets lists of objects into empManager using setManagedEmployees, setChildren, setProjects, setResponsibilityList, setPhoneNumbers methods. |
| * The list should be created with createList method. |
| */ |
| void setListInto(Employee empManager, List<List> listOfLists) { |
| int i = 0; |
| if(useManagedEmployees) { |
| List<Employee> newList = listOfLists.get(i++); |
| List<Employee> oldList = empManager.getManagedEmployees(); |
| empManager.setManagedEmployees(newList); |
| if(oldList != null) { |
| for(int j=0; j < oldList.size(); j++) { |
| oldList.get(j).setManager(null); |
| } |
| } |
| if(newList != null) { |
| for(int j=0; j < newList.size(); j++) { |
| newList.get(j).setManager(empManager); |
| } |
| } |
| } |
| if(useChildren) { |
| empManager.setChildren((Vector)listOfLists.get(i++)); |
| } |
| if(useProjects) { |
| List<Project> newList = listOfLists.get(i++); |
| List<Project> oldList = empManager.getProjects(); |
| empManager.setProjects(newList); |
| if(oldList != null) { |
| for(int j=0; j < oldList.size(); j++) { |
| oldList.get(j).getEmployees().remove(empManager); |
| } |
| } |
| if(newList != null) { |
| for(int j=0; j < newList.size(); j++) { |
| newList.get(j).getEmployees().add(empManager); |
| } |
| } |
| } |
| if(useResponsibilities) { |
| empManager.setResponsibilitiesList(listOfLists.get(i++)); |
| } |
| if(usePhones) { |
| empManager.setPhoneNumbers(listOfLists.get(i++)); |
| } |
| } |
| |
| /* |
| * Updates a list of objects that could be added to manager: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * Note that indexForName here is used as part of a state of the object being updated - not as its position in any list. |
| */ |
| void update( List list, String prefix, int indexForName) { |
| String iString = Integer.toString(indexForName); |
| int i = 0; |
| if(useManagedEmployees) { |
| Employee emp = (Employee)list.get(i++); |
| emp.setFirstName(iString); |
| emp.setLastName(prefix); |
| } |
| if(useChildren) { |
| Child child = (Child)list.get(i++); |
| child.setFirstName(iString); |
| child.setLastName(prefix); |
| } |
| if(useProjects) { |
| Project project = (Project)list.get(i++); |
| project.setName(iString); |
| } |
| if(useResponsibilities) { |
| throw new TestProblemException("Can't update a String. Set useResponsibilities to false"); |
| } |
| if(usePhones) { |
| if(prefix.length() > 3) { |
| prefix = prefix.substring(0, 3); |
| } |
| PhoneNumber phone = (PhoneNumber)list.get(i++); |
| phone.setAreaCode(prefix); |
| phone.setNumber(iString); |
| } |
| } |
| |
| /* |
| * Registers in uow a list of mapped non-aggregated objects that could be added to manager: Employee, Child, Project. |
| * Returns a list that contains clones that could be updated. |
| */ |
| List register(List list, UnitOfWork uow) { |
| ArrayList listClone = new ArrayList(list.size()); |
| int i = 0; |
| if(useManagedEmployees) { |
| listClone.add(uow.registerObject(list.get(i++))); |
| } |
| if(useChildren) { |
| listClone.add(uow.registerObject(list.get(i++))); |
| } |
| if(useProjects) { |
| listClone.add(uow.registerObject(list.get(i++))); |
| } |
| if(useResponsibilities) { |
| throw new TestProblemException("Can't register a String in uow. Set useResponsibilities to false"); |
| } |
| if(usePhones) { |
| throw new TestProblemException("Can't register aggregate in uow. Set usePhones to false"); |
| } |
| return listClone; |
| } |
| |
| /* |
| * Creates a list of Lists that could be set to manager: List<Employee>, Vector, List<Project>, List<String>, List<PhoneNumber>. |
| */ |
| List<List> createList() { |
| List<List> listOfLists = new ArrayList(); |
| if(useManagedEmployees) { |
| listOfLists.add(new ArrayList<Employee>()); |
| } |
| if(useChildren) { |
| listOfLists.add(new Vector()); |
| } |
| if(useProjects) { |
| listOfLists.add(new ArrayList<Project>()); |
| } |
| if(useResponsibilities) { |
| listOfLists.add(new ArrayList<String>()); |
| } |
| if(usePhones) { |
| listOfLists.add(new ArrayList<PhoneNumber>()); |
| } |
| return listOfLists; |
| } |
| |
| /* |
| * Adds a list of objects to listOfLists: Employee, Child, Project, Responsibility (String), PhoneNumber. |
| * listOfLists should be created with createList method. |
| * list should be obtained from getFrom, create, removeFrom or setInto methods. |
| */ |
| void addTo(List<List> listOfLists, List list) { |
| int i = 0; |
| if(useManagedEmployees) { |
| listOfLists.get(i).add(list.get(i++)); |
| } |
| if(useChildren) { |
| listOfLists.get(i).add(list.get(i++)); |
| } |
| if(useProjects) { |
| listOfLists.get(i).add(list.get(i++)); |
| } |
| if(useResponsibilities) { |
| listOfLists.get(i).add(list.get(i++)); |
| } |
| if(usePhones) { |
| listOfLists.get(i).add(list.get(i++)); |
| } |
| } |
| |
| /* |
| * Breaks order in the db by assigning wrong values to order fields |
| */ |
| String getManagegedEmployeesOrderTable() { |
| return useSecondaryTable ? "OL_SALARY" : "OL_EMPLOYEE"; |
| } |
| String getManagegedEmployeesOrderField() { |
| return useVarcharOrder ? "MANAGED_ORDER_VARCHAR" : "MANAGED_ORDER"; |
| } |
| void breakManagedEmployeesOrder() { |
| executeBreak(getManagegedEmployeesOrderTable(), getManagegedEmployeesOrderField(), "1", "NULL"); |
| } |
| String getChildrenOrderTable() { |
| return useSecondaryTable ? "OL_ALLOWANCE" : "OL_CHILD"; |
| } |
| String getChildrenOrderField() { |
| return useVarcharOrder ? "CHILDREN_ORDER_VARCHAR" : "CHILDREN_ORDER"; |
| } |
| void breakChildrenOrder() { |
| executeBreak(getChildrenOrderTable(), getChildrenOrderField(), "0", "NULL"); |
| } |
| void breakProjectsOrder() { |
| String tableName = "OL_PROJ_EMP"; |
| String fieldName; |
| if(useVarcharOrder) { |
| fieldName = "PROJ_ORDER_VARCHAR"; |
| } else { |
| fieldName = "PROJ_ORDER"; |
| } |
| executeBreak(tableName, fieldName, "0", "5"); |
| } |
| void breakResponsibilitiesOrder() { |
| String tableName = "OL_RESPONS"; |
| String fieldName; |
| if(useVarcharOrder) { |
| fieldName = "RESPONS_ORDER_VARCHAR"; |
| } else { |
| fieldName = "RESPONS_ORDER"; |
| } |
| executeBreak(tableName, fieldName, "1", "0"); |
| } |
| void breakPhonesOrder() { |
| String tableName = "OL_PHONE"; |
| String fieldName; |
| if(useVarcharOrder) { |
| fieldName = "PHONE_ORDER_VARCHAR"; |
| } else { |
| fieldName = "PHONE_ORDER"; |
| } |
| executeBreak(tableName, fieldName, "0", "1"); |
| } |
| void executeBreak(String tableName, String fieldName, String oldValue, String newValue) { |
| getSession().executeNonSelectingSQL("UPDATE "+tableName+" SET "+fieldName+" = "+newValue+" WHERE "+fieldName+" = " + oldValue); |
| } |
| void breakOrder() { |
| if(useManagedEmployees) { |
| breakManagedEmployeesOrder(); |
| } |
| if(useChildren) { |
| breakChildrenOrder(); |
| } |
| if(useProjects) { |
| breakProjectsOrder(); |
| } |
| if(useResponsibilities) { |
| breakResponsibilitiesOrder(); |
| } |
| if(usePhones) { |
| breakPhonesOrder(); |
| } |
| } |
| |
| /* |
| * Set the new OrderCorrectionType, return the old one. |
| * Verify that the old modes are the same for all mappings. |
| */ |
| OrderCorrectionType changeOrderCorrectionType(OrderCorrectionType mode) { |
| OrderCorrectionType oldMode = null; |
| if(useManagedEmployees) { |
| oldMode = changeOrderCorrectionType("managedEmployees", mode, oldMode); |
| } |
| if(useChildren) { |
| oldMode = changeOrderCorrectionType("children", mode, oldMode); |
| } |
| if(useProjects) { |
| oldMode = changeOrderCorrectionType("projects", mode, oldMode); |
| } |
| if(useResponsibilities) { |
| oldMode = changeOrderCorrectionType("responsibilitiesList", mode, oldMode); |
| } |
| if(usePhones) { |
| oldMode = changeOrderCorrectionType("phoneNumbers", mode, oldMode); |
| } |
| return oldMode; |
| } |
| OrderCorrectionType changeOrderCorrectionType(String attribute, OrderCorrectionType mode, OrderCorrectionType oldMode) { |
| ClassDescriptor desc = getSession().getDescriptor(Employee.class); |
| CollectionMapping mapping = (CollectionMapping)desc.getMappingForAttributeName(attribute); |
| OrderCorrectionType currOldMode = changeOrderCorrectionType(mapping, mode); |
| if(oldMode != null) { |
| if(oldMode != currOldMode) { |
| throw new TestProblemException("OrderCorrectionTypes for " + attribute+ " is " + currOldMode +"; for previous mapping(s) it was " + oldMode); |
| } |
| } |
| return currOldMode; |
| } |
| OrderCorrectionType changeOrderCorrectionType(CollectionMapping mapping, OrderCorrectionType mode) { |
| OrderedListContainerPolicy policy = (OrderedListContainerPolicy)mapping.getContainerPolicy(); |
| OrderCorrectionType oldMode = policy.getOrderCorrectionType(); |
| policy.setOrderCorrectionType(mode); |
| |
| OrderedListContainerPolicy queryPolicy = null; |
| if(mapping.getSelectionQuery().isReadAllQuery()) { |
| queryPolicy = (OrderedListContainerPolicy)((ReadAllQuery)mapping.getSelectionQuery()).getContainerPolicy(); |
| } else if(mapping.getSelectionQuery().isDataReadQuery()) { |
| queryPolicy = (OrderedListContainerPolicy)((DataReadQuery)mapping.getSelectionQuery()).getContainerPolicy(); |
| } |
| if(policy != queryPolicy) { |
| OrderCorrectionType oldModeQuery = queryPolicy.getOrderCorrectionType(); |
| if(oldMode != oldModeQuery) { |
| throw new TestErrorException(mapping.getAttributeName() + ": OrderCorrectionTypes in container policy is " + oldMode +"; is query is " + oldModeQuery); |
| } |
| queryPolicy.setOrderCorrectionType(mode); |
| } |
| return oldMode; |
| } |
| |
| /* |
| * Verify IndirectList.isListOrderBrokenInDb flag value. |
| * Throw exception if it's not expected one. |
| */ |
| String verifyIsListOrderBrokenInDb(Employee empManager, boolean expected) { |
| String localErrorMsg = ""; |
| if(useManagedEmployees) { |
| localErrorMsg += verifyIsListOrderBrokenInDb(empManager, expected, "managedEmployees"); |
| } |
| if(useChildren) { |
| localErrorMsg += verifyIsListOrderBrokenInDb(empManager, expected, "children"); |
| } |
| if(useProjects) { |
| localErrorMsg += verifyIsListOrderBrokenInDb(empManager, expected, "projects"); |
| } |
| if(useResponsibilities) { |
| localErrorMsg += verifyIsListOrderBrokenInDb(empManager, expected, "responsibilitiesList"); |
| } |
| if(usePhones) { |
| localErrorMsg += verifyIsListOrderBrokenInDb(empManager, expected, "phoneNumbers"); |
| } |
| if(localErrorMsg.length() > 0) { |
| localErrorMsg = "isListOrderBrokenInDb expected to be " + expected + ". For the following attributes it is " + !expected +": " + localErrorMsg; |
| } |
| return localErrorMsg; |
| } |
| String verifyIsListOrderBrokenInDb(Employee empManager, boolean expected, String attribute) { |
| String localErrorMsg = ""; |
| ClassDescriptor desc = getSession().getDescriptor(Employee.class); |
| CollectionMapping mapping = (CollectionMapping)desc.getMappingForAttributeName(attribute); |
| Object attributeValue = mapping.getRealAttributeValueFromObject(empManager, getAbstractSession()); |
| if(((IndirectList)attributeValue).isListOrderBrokenInDb() != expected) { |
| localErrorMsg = attribute + "; "; |
| } |
| return localErrorMsg; |
| } |
| |
| /* |
| * Indicates whether all lists were read in |
| */ |
| boolean isInstantiated(Employee empManager) { |
| List list; |
| String instantiatedStr = ""; |
| String notInstantiatedStr = ""; |
| String str; |
| boolean isInstantiated; |
| if(useManagedEmployees) { |
| list = empManager.getManagedEmployees(); |
| isInstantiated = isInstantiated(list); |
| str = (isInstantiated ? instantiatedStr : notInstantiatedStr); |
| str += "managedEmployees; "; |
| } |
| if(useChildren) { |
| list = empManager.getChildren(); |
| isInstantiated = isInstantiated(list); |
| str = (isInstantiated ? instantiatedStr : notInstantiatedStr); |
| str += "children; "; |
| } |
| if(useProjects) { |
| list = empManager.getProjects(); |
| isInstantiated = isInstantiated(list); |
| str = (isInstantiated ? instantiatedStr : notInstantiatedStr); |
| str += "projects; "; |
| } |
| if(useResponsibilities) { |
| list = empManager.getResponsibilitiesList(); |
| isInstantiated = isInstantiated(list); |
| str = (isInstantiated ? instantiatedStr : notInstantiatedStr); |
| str += "responsibilities; "; |
| } |
| if(usePhones) { |
| list = empManager.getPhoneNumbers(); |
| isInstantiated = isInstantiated(list); |
| str = (isInstantiated ? instantiatedStr : notInstantiatedStr); |
| str += "phoneNumbers; "; |
| } |
| if(instantiatedStr.length() > 0 && notInstantiatedStr.length() > 0) { |
| throw new TestProblemException("Some attributes are instantiated: " + instantiatedStr + " and some are not: " + notInstantiatedStr); |
| } else { |
| return instantiatedStr.length() > 0; |
| } |
| } |
| boolean isInstantiated(List list) { |
| return !(list instanceof IndirectList && !((IndirectList)list).isInstantiated()); |
| } |
| |
| String getShortClassName() { |
| String name = this.getClass().getName(); |
| int begin = name.indexOf('$') + 1; |
| int end = name.length(); |
| return name.substring(begin, end); |
| } |
| } |
| |
| /* |
| * Base class for tests using Employee manager object. |
| * createManager method creates a manager with nSize of managedEmployees, children, projects, responsibilities, phones. |
| */ |
| class BaseManagerTest extends BaseTest { |
| /* |
| * Number of manager's managedEmployees, children, projects, responsibilities, phones |
| * created by createManager method. |
| */ |
| int nSize; |
| |
| Employee manager; |
| /* |
| * manager's clone in uow. |
| */ |
| Employee managerClone; |
| |
| BaseManagerTest() { |
| super(); |
| this.nSize = 2; |
| } |
| |
| /* |
| * Creates manager with nSize members |
| */ |
| void createManager() { |
| manager = new Employee("Manager"); |
| for(int i=0; i < nSize; i++) { |
| this.addTo(manager, create("old", i)); |
| } |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| uow.commit(); |
| } |
| |
| @Override |
| protected void verify() { |
| if(manager == null) { |
| throw new TestErrorException("manager == null. Nothing to verify"); |
| } |
| |
| String textNameExt; |
| for(int k=0; k<2; k++) { |
| if(k == 0) { |
| textNameExt = "Cache"; |
| } else { |
| textNameExt = "DB"; |
| |
| // Read back the inserted objects, make sure the order is correct. |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| manager = (Employee)getSession().readObject(manager); |
| } |
| if(!getAbstractSession().compareObjects(managerClone, manager)) { |
| errorMsg += textNameExt + ": " + "objects not equal\n"; |
| } |
| } |
| if(errorMsg.length() > 0) { |
| throw new TestErrorException('\n' + errorMsg); |
| } |
| } |
| |
| // assumes that listToVerify is in cache and contains mapped object only (can't contain, say String). |
| protected void verifyList(List listToVerify, List listToCompareTo) { |
| if(listToVerify == null) { |
| throw new TestErrorException("listToVerify is null. Nothing to verify"); |
| } |
| int size = listToVerify.size(); |
| String textNameExt; |
| for(int k=0; k<2; k++) { |
| if(k == 0) { |
| textNameExt = "Cache"; |
| } else { |
| textNameExt = "DB"; |
| |
| // Read back the objects from db |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| for(int i=0; i < size; i++) { |
| listToVerify.set(i, getSession().readObject(listToVerify.get(i))); |
| } |
| } |
| for(int i=0; i < size; i++) { |
| Object toVerify = listToVerify.get(i); |
| Object toCompareTo = listToCompareTo.get(i); |
| if(!getAbstractSession().compareObjects(toCompareTo, toVerify)) { |
| errorMsg += textNameExt + ": " + "objects not equal\n"; |
| } |
| } |
| } |
| } |
| |
| // verifies that listToVerify is not in cache and not in db. listToVerify contains mapped object only (can't contain, say String). |
| protected void verifyListRemoved(List listToVerify) { |
| if(listToVerify == null) { |
| throw new TestErrorException("listToVerify is null. Nothing to verify"); |
| } |
| int size = listToVerify.size(); |
| String textNameExt; |
| for(int k=0; k<2; k++) { |
| if(k == 0) { |
| textNameExt = "Cache"; |
| |
| for(int i=0; i < size; i++) { |
| ReadObjectQuery query = new ReadObjectQuery(); |
| query.setSelectionObject(listToVerify.get(i)); |
| query.checkCacheOnly(); |
| Object readObject = getSession().executeQuery(query); |
| if(readObject != null) { |
| errorMsg += textNameExt + ": " + readObject + " was not removed\n"; |
| } |
| } |
| } else { |
| textNameExt = "DB"; |
| |
| // Read back the objects from db |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| for(int i=0; i < size; i++) { |
| Object readObject = getSession().readObject(listToVerify.get(i)); |
| if(readObject != null) { |
| errorMsg += textNameExt + ": " + readObject + " was not removed\n"; |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void reset() { |
| super.reset(); |
| manager = null; |
| managerClone = null; |
| } |
| |
| String nSizeName() { |
| return getShortClassName() + ": "+nSize+":"; |
| } |
| } |
| |
| /* |
| * Create manager, save to the db, verify that it was correctly merged into shared cache and written into the db. |
| */ |
| class CreateTest extends BaseManagerTest { |
| CreateTest() { |
| super(); |
| } |
| @Override |
| public void test() { |
| createManager(); |
| } |
| } |
| |
| /* |
| * Create empty manager, save to the db, verify that it was correctly merged into shared cache and written into the db. |
| * For OUTER_JOIN case to verify that read back lists are empty (as opposed to having null members). |
| */ |
| class CreateEmptyTest extends CreateTest { |
| CreateEmptyTest() { |
| super(); |
| nSize = 0; |
| } |
| } |
| |
| /* |
| * Create manager, save to the db. Meant as a base to the tests that change manager. |
| */ |
| class ChangeTest extends BaseManagerTest { |
| ChangeTest() { |
| super(); |
| } |
| @Override |
| public void setup() { |
| super.setup(); |
| createManager(); |
| } |
| } |
| |
| /* |
| * Switch positions of list members. |
| * [0, 2], [7, 5] means that old[0] = new[7], old[2] = new[5]; |
| * [0, 2, 5], [7, 5, 4] means that old[0] = new[7], old[2] = new[5], old[5] = new[4]. |
| * useSet indicates whether to use set(index, obj) method or remove(index)/add(index, obj). |
| */ |
| class TranspositionTest extends ChangeTest { |
| int[] oldIndexes, newIndexes; |
| boolean useSet; |
| /* |
| * nSize is number of members in each of the lists (managedEmployees, children etc), it should be greater than any old or new index |
| */ |
| TranspositionTest(int nSize, int[] oldIndexes, int[] newIndexes, boolean useSet) { |
| super(); |
| this.nSize = nSize; |
| this.oldIndexes = oldIndexes; |
| this.newIndexes = newIndexes; |
| this.useSet = useSet; |
| verifyIndexes(); |
| for(int i=0; i<oldIndexes.length; i++) { |
| if(oldIndexes[i] >= nSize) { |
| throw new TestProblemException("oldIndex["+i+"] = "+oldIndexes[i]+", which is greater than nSize ="+nSize); |
| } |
| if(newIndexes[i] >= nSize) { |
| throw new TestProblemException("newIndex["+i+"] = "+newIndexes[i]+", which is greater than nSize ="+nSize); |
| } |
| } |
| setName(); |
| } |
| /* |
| * nSize is number of members in each of the lists (managedEmployees, children etc), |
| * it will be set to the max index + 1. |
| */ |
| TranspositionTest(int[] oldIndexes, int[] newIndexes, boolean useSet) { |
| super(); |
| this.oldIndexes = oldIndexes; |
| this.newIndexes = newIndexes; |
| this.useSet = useSet; |
| verifyIndexes(); |
| nSize = 0; |
| for(int i=0; i<oldIndexes.length; i++) { |
| if(oldIndexes[i] > nSize) { |
| nSize = oldIndexes[i]; |
| } |
| if(newIndexes[i] > nSize) { |
| nSize = newIndexes[i]; |
| } |
| } |
| nSize++; |
| setName(); |
| } |
| public void verifyIndexes() { |
| if(oldIndexes.length != newIndexes.length) { |
| throw new TestProblemException("oldIndexes.length != newIndexes.length"); |
| } |
| for(int i=0; i < oldIndexes.length; i++) { |
| int oldIndex = oldIndexes[i]; |
| boolean found = false; |
| for(int j=0; j < newIndexes.length; j++) { |
| if(oldIndex == newIndexes[j]) { |
| found = true; |
| break; |
| } |
| } |
| if(!found) { |
| throw new TestProblemException("oldIndexes["+i+"] value "+oldIndex+" not found in newIndexes"); |
| } |
| } |
| } |
| String toString(int[] array) { |
| String str = "["; |
| for(int i=0; i<array.length; i++) { |
| str += Integer.toString(array[i]); |
| if(i < array.length-1) { |
| str += ", "; |
| } else { |
| str += "]"; |
| } |
| } |
| return str; |
| } |
| void setName() { |
| setName(getName() + " " + toString(oldIndexes) + " -> " + toString(newIndexes) + (useSet ? " set" : " remove/add")); |
| } |
| public void transpose(UnitOfWork uow) { |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| int n = oldIndexes.length; |
| List[] lists = new ArrayList[n]; |
| for(int i=0; i<n; i++) { |
| lists[i] = getFrom(managerClone, oldIndexes[i]); |
| } |
| for(int i=0; i<n; i++) { |
| int newIndex = newIndexes[i]; |
| if(useSet) { |
| setInto_NoRelMaintanence(managerClone, newIndex, lists[i]); |
| } else { |
| removeFrom_NoRelMaintanence(managerClone, newIndex); |
| addTo_NoRelMaintanence(managerClone, newIndex, lists[i]); |
| } |
| } |
| } |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| transpose(uow); |
| uow.commit(); |
| } |
| } |
| |
| /* |
| * Same as TranspositionTest, but the owner of transposed lists is detached, then merged. |
| */ |
| class TranspositionMergeTest extends TranspositionTest { |
| // This test transposes objects in detached collection, doesn't care whether set or remove/add |
| TranspositionMergeTest(int nSize, int[] oldIndexes, int[] newIndexes) { |
| super(nSize, oldIndexes, newIndexes, true); |
| } |
| TranspositionMergeTest(int[] oldIndexes, int[] newIndexes) { |
| // This test transposes objects in detached collection, doesn't care whether set or remove/add |
| super(oldIndexes, newIndexes, true); |
| } |
| @Override |
| void setName() { |
| setName(getName() + " " + toString(oldIndexes) + " -> " + toString(newIndexes)); |
| } |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| transpose(uow); |
| uow.unregisterObject(this.managerClone); |
| uow.release(); |
| |
| uow = getSession().acquireUnitOfWork(); |
| this.managerClone = (Employee)uow.mergeCloneWithReferences(this.managerClone); |
| uow.commit(); |
| } |
| } |
| |
| /* |
| * For each mapping: add one new object, remove one existing object |
| */ |
| class SimpleAddRemoveTest extends ChangeTest { |
| SimpleAddRemoveTest() { |
| super(); |
| } |
| |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| addTo(managerClone, create("new", 1)); |
| removeFrom(managerClone, 0); |
| |
| uow.commit(); |
| } |
| } |
| |
| /* |
| * For each mapping: add one new object, remove one existing object |
| */ |
| class AddRemoveUpdateTest extends ChangeTest { |
| List removedList; |
| List removedListClone; |
| AddRemoveUpdateTest() { |
| super(); |
| } |
| |
| @Override |
| public void setup() { |
| // Strings are immutable - can't update. |
| useResponsibilities = false; |
| // Can't directly register an aggregate in uow. |
| usePhones = false; |
| super.setup(); |
| } |
| |
| @Override |
| public void test() { |
| // create a list of objects to be added |
| List newList = this.create("new", 0); |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| List newListClone = this.register(newList, uow); |
| uow.commit(); |
| |
| // save list to be removed |
| removedList = this.getFrom(manager, 0); |
| |
| uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| // update new list clone |
| newListClone = this.register(newList, uow); |
| update(newListClone, "updated", 0); |
| // add updated objects to managerClone |
| addTo(managerClone, newListClone); |
| |
| // remove from managerClone |
| removedListClone = removeFrom(managerClone, 0); |
| // update removed objects |
| update(removedListClone, "updated", 0); |
| |
| uow.commit(); |
| } |
| |
| @Override |
| public void verify() { |
| super.verify(); |
| if(isPrivatelyOwned) { |
| verifyListRemoved(removedList); |
| } else { |
| verifyList(removedList, removedListClone); |
| } |
| if(errorMsg.length() > 0) { |
| throw new TestErrorException('\n' + errorMsg); |
| } |
| } |
| } |
| |
| /* |
| * For each mapping: add one new object, remove one existing object |
| */ |
| class SimpleAddRemoveTest2 extends ChangeTest { |
| SimpleAddRemoveTest2() { |
| super(); |
| nSize = 12; |
| } |
| |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| addTo(managerClone, 0, create("new", 0)); |
| addTo(managerClone, 4, create("new", 4)); |
| removeFrom(managerClone, 8); |
| |
| uow.commit(); |
| } |
| } |
| |
| /* |
| * For each mapping: set a new object |
| */ |
| class SimpleSetTest extends ChangeTest { |
| SimpleSetTest() { |
| super(); |
| } |
| |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| setInto(managerClone, 1, create("new", 1)); |
| |
| uow.commit(); |
| } |
| } |
| |
| /* |
| * For each mapping: create a new List of two objects, set the new List into managerClone; |
| * if useSet is not null, before setting a new list either add or set a new object into the old list. |
| */ |
| class SimpleSetListTest extends ChangeTest { |
| Boolean useSet; |
| SimpleSetListTest() { |
| super(); |
| } |
| SimpleSetListTest(boolean useSet) { |
| super(); |
| this.useSet = useSet; |
| setName(getName() + (useSet ? " set" : " remove/add")); |
| } |
| |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| if(useSet != null) { |
| if(useSet) { |
| setInto(managerClone, 1, create("temp", 1)); |
| } else { |
| addTo(managerClone, create("temp", 2)); |
| } |
| } |
| List<List> list = createList(); |
| addTo(list, create("new", 0)); |
| addTo(list, create("new", 1)); |
| setListInto(managerClone, list); |
| |
| uow.commit(); |
| } |
| } |
| |
| class SimpleIndexTest extends ChangeTest { |
| int min; |
| int max; |
| int nExpected; |
| boolean useIndex; |
| |
| SimpleIndexTest(boolean useIndex) { |
| super(); |
| nSize = 12; |
| min = 1; |
| max = 4; |
| nExpected = max - min + 1; |
| |
| this.useIndex = useIndex; |
| setName(getName() + (useIndex ? " use index()" : " use getField()")); |
| } |
| @Override |
| public void test() { |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| if(useManagedEmployees) { |
| test("managedEmployees"); |
| } |
| if(useChildren) { |
| test("children"); |
| } |
| if(useProjects) { |
| test("projects"); |
| } |
| if(useResponsibilities) { |
| test("responsibilitiesList"); |
| } |
| if(usePhones) { |
| test("phoneNumbers"); |
| } |
| } |
| void test(String attributeName) { |
| ReportQuery query = new ReportQuery(); |
| query.setReferenceClass(Employee.class); |
| ExpressionBuilder builder = query.getExpressionBuilder(); |
| Expression exp; |
| Expression firstNameManager = builder.get("firstName").equal("Manager"); |
| Expression anyOfAttribute = builder.anyOf(attributeName); |
| if(useIndex) { |
| // tests index() expression |
| exp = firstNameManager.and(anyOfAttribute.index().between(min, max)); |
| } else { |
| // tests getField() expression (or getTable().getField() expression) equivalent to index(). |
| if(isTableExpressionRequired(attributeName)) { |
| exp = firstNameManager.and(anyOfAttribute.getTable(getTableName(attributeName)).getField(getFieldName(attributeName)).between(min, max)); |
| } else { |
| exp = firstNameManager.and(anyOfAttribute.getField(getFieldName(attributeName)).between(min, max)); |
| } |
| } |
| query.setSelectionCriteria(exp); |
| query.addAttribute(attributeName, anyOfAttribute); |
| |
| ArrayList indexesRead = new ArrayList(nExpected); |
| boolean error = false; |
| List<ReportQueryResult> results = (List)getSession().executeQuery(query); |
| for(int i=0; i < results.size(); i++) { |
| ReportQueryResult result = results.get(i); |
| int index = getIndex(result.getResults().get(0), attributeName); |
| error |= max < index || index < min; |
| indexesRead.add(index); |
| } |
| String localErrorMsg = ""; |
| if(error) { |
| localErrorMsg += "Wrong index values read: " + indexesRead +"; expected all numbers between (inclusive) " + min + " and " + max; |
| } |
| // query with joins return Cartesian product of all rows - the same values returned more than once. |
| if(OrderListTestModel.this.joinFetchOrBatchRead != JoinFetchOrBatchRead.OUTER_JOIN && OrderListTestModel.this.joinFetchOrBatchRead != JoinFetchOrBatchRead.INNER_JOIN) { |
| if(indexesRead.size() != nExpected) { |
| localErrorMsg += attributeName + " Wrong number of objects read: " + indexesRead.size() +"; expected " + nExpected; |
| } |
| } |
| |
| if(localErrorMsg.length() > 0) { |
| localErrorMsg = attributeName + ": " + localErrorMsg + "\n"; |
| errorMsg += localErrorMsg; |
| } |
| } |
| /* |
| * all objects were constructed to incorporate the index, see createManager method. |
| */ |
| int getIndex(Object obj, String attributeName) { |
| int index = -1; |
| if(attributeName.equals("managedEmployees")) { |
| index = Integer.parseInt(((Employee)obj).getFirstName()); |
| } else if(attributeName.equals("children")) { |
| index = Integer.parseInt(((Child)obj).getFirstName()); |
| } else if(attributeName.equals("projects")) { |
| index = getNumberFromString(((Project)obj).getName()); |
| } else if(attributeName.equals("responsibilitiesList")) { |
| index = getNumberFromString((String)obj); |
| } else if(attributeName.equals("phoneNumbers")) { |
| index = Integer.parseInt(((PhoneNumber)obj).getNumber()); |
| } |
| return index; |
| } |
| int getNumberFromString(String str) { |
| int nEnd = str.length(); |
| int nStart = 0; |
| for(nStart=0; nStart < nEnd; nStart++) { |
| char ch = str.charAt(nStart); |
| if('0' <= ch && ch <='9') { |
| break; |
| } |
| } |
| str = str.substring(nStart); |
| return Integer.parseInt(str); |
| } |
| |
| @Override |
| protected void verify() { |
| if(errorMsg.length() > 0) { |
| errorMsg = "\n" + errorMsg; |
| throw new TestErrorException(errorMsg); |
| } |
| } |
| |
| /* |
| * ManyToMany and DirectCollection mapping require table name expression. |
| * Used to test getField() expression (or getTable().getField() expression) equivalent to index(). |
| */ |
| boolean isTableExpressionRequired(String attributeName) { |
| return attributeName.equals("projects") || attributeName.equals("responsibilitiesList"); |
| } |
| /* |
| * ManyToMany and DirectCollection mapping require table name expression. |
| * Used to test getTable().getField() expression equivalent to index(). |
| */ |
| String getTableName(String attributeName) { |
| if(attributeName.equals("projects")) { |
| return "OL_PROJ_EMP"; |
| } else if(attributeName.equals("responsibilitiesList")) { |
| return "OL_RESPONS"; |
| } else { |
| throw new TestProblemException(attributeName + " should not be looking for table name."); |
| } |
| } |
| /* |
| * Used to test getField() expression (or getTable().getField() expression) equivalent to index(). |
| */ |
| String getFieldName(String attributeName) { |
| String fieldName = null; |
| if(attributeName.equals("managedEmployees")) { |
| fieldName = "MANAGED_ORDER"; |
| } else if(attributeName.equals("children")) { |
| fieldName = "CHILDREN_ORDER"; |
| } else if(attributeName.equals("projects")) { |
| fieldName = "PROJ_ORDER"; |
| } else if(attributeName.equals("responsibilitiesList")) { |
| fieldName = "RESPONS_ORDER"; |
| } else if(attributeName.equals("phoneNumbers")) { |
| fieldName = "PHONE_ORDER"; |
| } |
| return fieldName; |
| } |
| } |
| |
| /* |
| * For each mapping: add object in front, or in the middle, or to the end of the list. |
| * Currently only DirectCollectionMapping supports duplicates and nulls. |
| * The test still uses all mappings so that it could be run with INNER_JOIN. |
| */ |
| abstract class WhereToAddTest extends ChangeTest { |
| String whereToAdd; |
| WhereToAddTest(String whereToAdd) { |
| super(); |
| this.whereToAdd = whereToAdd; |
| if(!front.equals(whereToAdd) && !middle.equals(whereToAdd) && !end.equals(whereToAdd)) { |
| throw new TestProblemException("Wrong whereToAdd = " + whereToAdd +"; Supported values: " + front +"; " +middle +"; " + end); |
| } |
| setName(getName() + " " + whereToAdd); |
| } |
| |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| |
| if(front.equals(whereToAdd)) { |
| addTo(managerClone, 0, objectToAdd()); |
| } else if(middle.equals(whereToAdd)) { |
| addTo(managerClone, 1, objectToAdd()); |
| } else if(end.equals(whereToAdd)) { |
| addTo(managerClone, objectToAdd()); |
| } |
| |
| uow.commit(); |
| } |
| |
| abstract List objectToAdd(); |
| } |
| |
| /* |
| * For each mapping: add null. |
| * Currently only DirectCollectionMapping supports nulls. |
| */ |
| class AddNullTest extends WhereToAddTest { |
| AddNullTest(String whereToAdd) { |
| super(whereToAdd); |
| } |
| @Override |
| List objectToAdd() { |
| List list = create("new", 0); |
| for(int i=0; i < list.size(); i++) { |
| if(list.get(i) instanceof String) { |
| // Currently only DirectCollectionMapping (responsibilities) supports nulls. |
| list.set(i, null); |
| break; |
| } |
| } |
| return list; |
| } |
| } |
| |
| /* |
| * For each mapping: add duplicate. |
| * Currently only DirectCollectionMapping supports duplicates. |
| */ |
| class AddDuplicateTest extends WhereToAddTest { |
| AddDuplicateTest(String whereToAdd) { |
| super(whereToAdd); |
| } |
| @Override |
| List objectToAdd() { |
| List newList = create("new", 0); |
| List oldList = getFrom(managerClone, 0); |
| // the two lists are of the same size |
| for(int i=0; i < newList.size(); i++) { |
| if(newList.get(i) instanceof String) { |
| // Currently only DirectCollectionMapping (responsibilities) supports duplicates. |
| newList.set(i, oldList.get(i)); |
| break; |
| } |
| } |
| return newList; |
| } |
| } |
| |
| /* |
| * Break the order in the db, read the lists (with broken order) back, get the expected exception. |
| * Note that a separate test required for each mapping to make sure they all throw correct exception. |
| */ |
| abstract class BreakOrderExceptionTest extends ChangeTest { |
| BreakOrderExceptionTest() { |
| super(); |
| if(orderCorrectionType != OrderCorrectionType.EXCEPTION) { |
| throw new TestProblemException("Requires OrderCorrectionType.EXCEPTION"); |
| } |
| } |
| @Override |
| abstract public void test(); |
| |
| @Override |
| protected void verify() { |
| try { |
| super.verify(); |
| throw new TestErrorException("Expected QueryException.LIST_ORDER_FIELD_WRONG_VALUE was not thrown."); |
| } catch (QueryException queryException) { |
| if(queryException.getErrorCode() == QueryException.LIST_ORDER_FIELD_WRONG_VALUE) { |
| // expected query exception on attempt to read broken order list |
| return; |
| } else { |
| throw queryException; |
| } |
| } |
| } |
| } |
| class BreakOrderExceptionTest_OneToMany extends BreakOrderExceptionTest { |
| BreakOrderExceptionTest_OneToMany() { |
| super(); |
| } |
| @Override |
| public void test() { |
| breakManagedEmployeesOrder(); |
| } |
| } |
| class BreakOrderExceptionTest_UnidirectionalOneToMany extends BreakOrderExceptionTest { |
| BreakOrderExceptionTest_UnidirectionalOneToMany() { |
| super(); |
| } |
| @Override |
| public void test() { |
| breakChildrenOrder(); |
| } |
| } |
| class BreakOrderExceptionTest_ManyToMany extends BreakOrderExceptionTest { |
| BreakOrderExceptionTest_ManyToMany() { |
| super(); |
| } |
| @Override |
| public void test() { |
| breakProjectsOrder(); |
| } |
| } |
| class BreakOrderExceptionTest_DirectCollection extends BreakOrderExceptionTest { |
| BreakOrderExceptionTest_DirectCollection() { |
| super(); |
| } |
| @Override |
| public void test() { |
| breakResponsibilitiesOrder(); |
| } |
| } |
| class BreakOrderExceptionTest_AggregateCollection extends BreakOrderExceptionTest { |
| BreakOrderExceptionTest_AggregateCollection() { |
| super(); |
| } |
| @Override |
| public void test() { |
| breakPhonesOrder(); |
| } |
| } |
| |
| /* |
| * bug 331144: Removing from a collection that is broken results in an |
| * ArrayIndexOutOfBoundsException when the collection is fixed. |
| */ |
| class BreakOrderCorrectionAndRemoveTest extends BreakOrderCorrectionTest { |
| BreakOrderCorrectionAndRemoveTest(boolean shoulReadManagerThroughUow) { |
| super(shoulReadManagerThroughUow); |
| } |
| @Override |
| public void test() { |
| breakOrder(); |
| |
| // clear cache to force reading back the objects |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| if(!shoulReadManagerThroughUow) { |
| // read in the object with broken order in the db |
| manager = (Employee)getSession().readObject(manager); |
| if(isInstantiated(manager)) { |
| // verify that all attribute values are marked as having broken order |
| errorMsg = this.verifyIsListOrderBrokenInDb(manager, true); |
| if(errorMsg.length() > 0) { |
| errorMsg = "manager in test: " + errorMsg; |
| throw new TestErrorException(errorMsg); |
| } |
| } |
| } |
| |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| if(shoulReadManagerThroughUow) { |
| managerClone = (Employee)uow.readObject(manager); |
| } else { |
| managerClone = (Employee)uow.registerObject(manager); |
| } |
| // remove element 1 |
| List list1 = removeFrom(managerClone, 1); |
| |
| // verify that all attribute values are marked as having broken order, |
| // at this point they should be instantiated |
| errorMsg = this.verifyIsListOrderBrokenInDb(managerClone, true); |
| if(errorMsg.length() > 0) { |
| errorMsg = "managerClone in test: " + errorMsg; |
| uow.release(); |
| throw new TestErrorException(errorMsg); |
| } |
| |
| try { |
| uow.commit(); |
| } catch (ArrayIndexOutOfBoundsException exception){ |
| throw new TestErrorException("Test received exception commit when fixing a broken collection", exception); |
| } |
| } |
| } |
| |
| /* |
| * Break the order in the db, read the lists (with broken order) back, update lists, write out updated lists. |
| * For verification temporary switch container policy into EXCEPTION mode, read back the list - |
| * exception thrown if the order is still broken. |
| */ |
| class BreakOrderCorrectionTest extends ChangeTest { |
| boolean shoulReadManagerThroughUow; |
| BreakOrderCorrectionTest(boolean shoulReadManagerThroughUow) { |
| super(); |
| this.nSize = 4; |
| this.shoulReadManagerThroughUow = shoulReadManagerThroughUow; |
| |
| if(orderCorrectionType != OrderCorrectionType.READ_WRITE) { |
| throw new TestProblemException("Requires OrderCorrectionType.CORRECTION"); |
| } |
| setName(getName() + (shoulReadManagerThroughUow ? " ReadThroughUow" : " ReadThroughSession")); |
| } |
| @Override |
| public void test() { |
| breakOrder(); |
| |
| // clear cache to force reading back the objects |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| if(!shoulReadManagerThroughUow) { |
| // read in the object with broken order in the db |
| manager = (Employee)getSession().readObject(manager); |
| if(isInstantiated(manager)) { |
| // verify that all attribute values are marked as having broken order |
| errorMsg = this.verifyIsListOrderBrokenInDb(manager, true); |
| if(errorMsg.length() > 0) { |
| errorMsg = "manager in test: " + errorMsg; |
| throw new TestErrorException(errorMsg); |
| } |
| } |
| } |
| |
| // change the order of elements 0 <-> 1 |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| if(shoulReadManagerThroughUow) { |
| managerClone = (Employee)uow.readObject(manager); |
| } else { |
| managerClone = (Employee)uow.registerObject(manager); |
| } |
| List list1 = removeFrom(managerClone, 1); |
| |
| // verify that all attribute values are marked as having broken order, |
| // at this point they should be instantiated |
| errorMsg = this.verifyIsListOrderBrokenInDb(managerClone, true); |
| if(errorMsg.length() > 0) { |
| errorMsg = "managerClone in test: " + errorMsg; |
| uow.release(); |
| throw new TestErrorException(errorMsg); |
| } |
| |
| List list0 = removeFrom(managerClone, 0); |
| addTo(managerClone, list1); |
| addTo(managerClone, list0); |
| |
| uow.commit(); |
| } |
| |
| @Override |
| protected void verify() { |
| OrderCorrectionType originalMode = this.changeOrderCorrectionType(OrderCorrectionType.EXCEPTION); |
| try { |
| if(shoulReadManagerThroughUow) { |
| // manager is not in shared cache - bring the one from the shared cache. |
| ReadObjectQuery query = new ReadObjectQuery(); |
| query.setReferenceClass(Employee.class); |
| query.checkCacheOnly(); |
| manager = (Employee)getSession().readObject(manager); |
| } |
| // verify that all attribute values are marked as having NOT broken order |
| errorMsg = this.verifyIsListOrderBrokenInDb(manager, false); |
| if(errorMsg.length() > 0) { |
| errorMsg = "manager in verify: " + errorMsg; |
| } |
| String localErrorMsg = this.verifyIsListOrderBrokenInDb(managerClone, false); |
| if(localErrorMsg.length() > 0) { |
| localErrorMsg = "managerClone in verify: " + localErrorMsg; |
| errorMsg += localErrorMsg; |
| } |
| super.verify(); |
| } finally { |
| this.changeOrderCorrectionType(originalMode); |
| } |
| } |
| } |
| |
| class BaseMultipleManagersTest extends BaseTest { |
| /* number of managers created by createManagers method.*/ |
| int nManagers; |
| /* |
| * Number of each manager's managedEmployees, children, projects, responsibilities, phones |
| * created by createManager method. |
| */ |
| int nSize; |
| |
| /* managers */ |
| List<Employee> managers = new ArrayList(nManagers); |
| /* their uow clones */ |
| List<Employee> managerClones = new ArrayList(nManagers); |
| |
| BaseMultipleManagersTest() { |
| super(); |
| nManagers = 2; |
| nSize = 2; |
| } |
| |
| /* |
| * Creates manager with nSize members |
| */ |
| void createManagers() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| |
| for(int i=0; i < nManagers; i++) { |
| String iStr = Integer.toString(i); |
| Employee manager = new Employee("Manager", iStr); |
| for(int j=0; j < nSize; j++) { |
| addTo(manager, create(iStr, j)); |
| } |
| Employee managerClone = (Employee)uow.registerObject(manager); |
| |
| managers.add(manager); |
| managerClones.add(managerClone); |
| } |
| |
| uow.commit(); |
| } |
| |
| @Override |
| public void reset() { |
| super.reset(); |
| managers.clear(); |
| managerClones.clear(); |
| } |
| |
| @Override |
| public void verify() { |
| if(managers == null || managers.isEmpty()) { |
| throw new TestErrorException("managers is null or empty. Nothing to verify"); |
| } |
| |
| String textNameExt; |
| for(int k=0; k<2; k++) { |
| if(k == 0) { |
| textNameExt = "Cache"; |
| } else { |
| textNameExt = "DB"; |
| |
| // Read back the inserted objects, make sure the order is correct. |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| ReadAllQuery query = new ReadAllQuery(); |
| query.setReferenceClass(Employee.class); |
| Expression exp = query.getExpressionBuilder().get("firstName").equal("Manager"); |
| query.setSelectionCriteria(exp); |
| query.addOrdering(query.getExpressionBuilder().get("lastName")); |
| |
| managers.clear(); |
| managers.addAll((List<Employee>)getSession().executeQuery(query)); |
| } |
| if(managers.size() != managerClones.size()) { |
| errorMsg = "wrong managers size " + managers.size() + "; expected size is " + managerClones.size(); |
| } else { |
| for(int i=0; i<managers.size(); i++) { |
| if(!getAbstractSession().compareObjects(managerClones.get(i), managers.get(i))) { |
| String localErrorMsg = textNameExt + ": " + "manager["+i+"] not equal\n"; |
| errorMsg += localErrorMsg; |
| } |
| } |
| } |
| } |
| if(errorMsg.length() > 0) { |
| throw new TestErrorException(errorMsg); |
| } |
| } |
| } |
| |
| /* |
| * Creates managers, verifies that they were correctly merged into cache and written to the db. |
| */ |
| class CreateManagersTest extends BaseMultipleManagersTest { |
| CreateManagersTest() { |
| super(); |
| } |
| |
| @Override |
| public void setup() { |
| createManagers(); |
| } |
| } |
| |
| /* |
| * Creates empty managers, verifies that they were correctly merged into cache and written to the db. |
| * For OUTER_JOIN case to verify that read back lists are empty (as opposed to having null members). |
| */ |
| class CreateEmptyManagersTest extends CreateManagersTest { |
| CreateEmptyManagersTest() { |
| super(); |
| nSize = 0; |
| } |
| } |
| |
| /* |
| * Verify that for each mapping both its container policy and its select query's container policy |
| * are of the expected type. |
| */ |
| class VerifyContainerPolicyClassTest extends TestCase { |
| Class expectedClass; |
| VerifyContainerPolicyClassTest() { |
| this(NullsLastOrderedListContainerPolicy.class); |
| } |
| VerifyContainerPolicyClassTest(Class expectedClass) { |
| super(); |
| this.expectedClass = expectedClass; |
| setName("VerifyContainerPolicyClassTest"); |
| } |
| @Override |
| public void verify() { |
| String errorMsg = ""; |
| List<CollectionMapping> listOrderMappings = EmployeeSystem.getListOrderMappings(getDatabaseSession()); |
| for(int i=0; i < listOrderMappings.size(); i++) { |
| CollectionMapping mapping = listOrderMappings.get(i); |
| if(!mapping.getContainerPolicy().getClass().equals(expectedClass)) { |
| errorMsg += mapping.getAttributeName() + ".containerPolicy type is wrong; "; |
| } |
| ReadQuery selectQuery = mapping.getSelectionQuery(); |
| if(selectQuery.isReadAllQuery()) { |
| if(!((ReadAllQuery)selectQuery).getContainerPolicy().getClass().equals(expectedClass)) { |
| errorMsg += mapping.getAttributeName() + ".queryContainerPolicy type is wrong; "; |
| } |
| } else { |
| if(!((DataReadQuery)selectQuery).getContainerPolicy().getClass().equals(expectedClass)) { |
| errorMsg += mapping.getAttributeName() + ".queryContainerPolicy type is wrong; "; |
| } |
| } |
| } |
| if(errorMsg.length() > 0) { |
| throw new TestErrorException(errorMsg); |
| } |
| } |
| } |
| |
| /* |
| * Test for OneToMany and UnideirectionalOneToMany mappings only: |
| * verify that the row in the db corresponding to the removed object |
| * has its order field value set to null. |
| */ |
| class VerifyForeignKeyOfRemovedObject extends ChangeTest { |
| boolean deleteSourceObject; |
| VerifyForeignKeyOfRemovedObject(boolean deleteSourceObject) { |
| super(); |
| this.deleteSourceObject = deleteSourceObject; |
| setName(getShortClassName() + (deleteSourceObject ? "_deleteSource" : "_removeTarget")); |
| } |
| // Only tests OneToMany and UnideirectionalOneToMany |
| @Override |
| public void setup() { |
| this.usePhones = false; |
| this.useProjects = false; |
| this.useResponsibilities = false; |
| super.setup(); |
| } |
| @Override |
| public void test() { |
| UnitOfWork uow = getSession().acquireUnitOfWork(); |
| managerClone = (Employee)uow.registerObject(manager); |
| if(deleteSourceObject) { |
| for(int i=0; i < nSize; i++) { |
| if(useManagedEmployees) { |
| managerClone.getManagedEmployees().get(i).setManager(null); |
| } |
| } |
| uow.deleteObject(managerClone); |
| } else { |
| for(int i=nSize-1; 0 <= i; i--) { |
| if(useManagedEmployees) { |
| managerClone.removeManagedEmployee(i); |
| } |
| if(useChildren) { |
| managerClone.getChildren().remove(i); |
| } |
| } |
| } |
| uow.commit(); |
| } |
| @Override |
| public void verify() { |
| // assume (as usual) that there were no objects in the db when the test started, |
| // then all the objects left should have their order set to null (including manager if not deleted). |
| if(useManagedEmployees) { |
| String sqlString = "SELECT COUNT(*) FROM "+this.getManagegedEmployeesOrderTable()+" WHERE "+this.getManagegedEmployeesOrderField()+" IS NOT NULL"; |
| int nonNulls = ((Number)((AbstractRecord)getSession().executeSQL(sqlString).get(0)).getValues().get(0)).intValue(); |
| if(nonNulls != 0) { |
| errorMsg += "useManagedEmployees has "+nonNulls+" non nulls; "; |
| } |
| } |
| if(useChildren) { |
| String sqlString = "SELECT COUNT(*) FROM "+this.getChildrenOrderTable()+" WHERE "+this.getChildrenOrderField()+" IS NOT NULL"; |
| int nonNulls = ((Number)((AbstractRecord)getSession().executeSQL(sqlString).get(0)).getValues().get(0)).intValue(); |
| if(nonNulls != 0) { |
| errorMsg += "useManagedEmployees has "+nonNulls+" non nulls; "; |
| } |
| } |
| } |
| } |
| } |