From 1633b4361687fcab0fd224bafcc141c5f2d35793 Mon Sep 17 00:00:00 2001 From: Jon Davis Date: Thu, 20 Aug 2015 00:42:28 -0700 Subject: [PATCH 1/3] Issue #229 - tests to demonstrate issue Note that this commit contains extra debug statements to make observing actual vs expected result easier. The debug statements will be removed if this issue is determined to be valid and PR accepted. --- rolluptool/src/classes/RollupServiceTest4.cls | 974 ++++++++++++++++++ 1 file changed, 974 insertions(+) diff --git a/rolluptool/src/classes/RollupServiceTest4.cls b/rolluptool/src/classes/RollupServiceTest4.cls index 99e422cb..3bab5614 100644 --- a/rolluptool/src/classes/RollupServiceTest4.cls +++ b/rolluptool/src/classes/RollupServiceTest4.cls @@ -137,4 +137,978 @@ private class RollupServiceTest4 { } return testUser; } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two identical Aggregate (Sum) rollups + * - Effective values for all fields except for AggregateResultField__c are same + * - Field values differ by case only + * - Field value of RelationShipCriteria__c is identical including case + * only by case used for rollups summary field values except RelationShipCriteria__c which are identical including case + * Should result in a single context used, a single SOQL for the rollup itself and 3 DML rows (1 for each parent) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleAggregateRollupsDifferByCaseOnlySameCriteriaSameCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Total__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition; + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryA.FieldToAggregate__c = aggregateField.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.Sum.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Sum.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, 20); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, 20); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, 2); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup + System.assertEquals(beforeQueries + 2, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c + System.assertEquals(beforeRows + 11, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c (from rollup processing) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two identical Aggregate (Sum) rollups + * - Effective values for all fields except AggregateResultField__c are same + * - Field values differ only by case + * - Field value of RelationShipCriteria__c differs by case + * Should result in Two (2) contexts used, two SOQL for the rollup itself and 3 DML rows (1 for each + * parent - DLRS combines updates to identical master record ids) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleAggregateRollupsDifferByCaseOnlySameCriteriaDiffCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Total__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition.toLowerCase(); + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields.toLowerCase(); + rollupSummaryA.FieldToAggregate__c = aggregateField.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.Sum.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Sum.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, 20); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, 20); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, 2); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup A + // + One query on LookupChild__c for rollup B + System.assertEquals(beforeQueries + 3, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c for rollup A + // + Nine rows for LookupChild__c for rollup B + System.assertEquals(beforeRows + 20, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c for rollup A & B (DLRS combined updates to identical master ids) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two identical Query (Last) rollups + * - Effective values for all fields except for AggregateResultField__c are same + * - Field values differ by case only + * - Field value of RelationShipCriteria__c is identical including case + * only by case used for rollups summary field values except RelationShipCriteria__c which are identical including case + * Should result in a single context used, a single SOQL for the rollup itself and 3 DML rows (1 for each parent) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleQueryRollupsDifferByCaseOnlySameCriteriaSameCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Total__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition; + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryA.FieldToAggregate__c = aggregateField.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, 42); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, 10); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, 10); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup + System.assertEquals(beforeQueries + 2, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c + System.assertEquals(beforeRows + 11, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c (from rollup processing) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two identical Query (Last) rollups + * - Effective values for all fields except AggregateResultField__c are same + * - Field values differ only by case + * - Field value of RelationShipCriteria__c differs by case + * Should result in Two (2) contexts used, two SOQL for the rollup itself and 3 DML rows (1 for each + * parent - DLRS combines updates to identical master record ids) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleQueryRollupsDifferByCaseOnlySameCriteriaDiffCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Total__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition.toLowerCase(); + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields.toLowerCase(); + rollupSummaryA.FieldToAggregate__c = aggregateField.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField, 42); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField, 10); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField, 10); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup A + // + One query on LookupChild__c for rollup B + System.assertEquals(beforeQueries + 3, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c for rollup A + // + Nine rows for LookupChild__c for rollup B + System.assertEquals(beforeRows + 20, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c for rollup A & B (DLRS combined updates to identical master ids) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two similar rollups + * - Different AggregateOperation__c (both use Query rollup - First/Last) + * - Different AggregateResultField__c + * - Different FieldToAggregate__c + * - Field value of RelationShipCriteria__c is identical including case + * - Effective values for all other fields same differing only by case used + * Should result in a single context used, a single SOQL for the rollup itself and 3 DML rows (1 for each parent) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleQueryRollupsDifferByOperationFieldAndCaseSameCriteriaSameCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField1 = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateField2 = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Colours__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition; + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryA.FieldToAggregate__c = aggregateField1.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.First.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField2; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField1, 'Red'); + child1.put(aggregateField2, 42); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField1, 'Yellow'); + child2.put(aggregateField2, 15); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField1, 'Blue'); + child3.put(aggregateField2, 10); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup + System.assertEquals(beforeQueries + 2, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c + System.assertEquals(beforeRows + 11, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c (from rollup processing) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals('Blue', (String) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two similar rollups + * - Different AggregateOperation__c (both use Query rollup - First/Last) + * - Different AggregateResultField__c + * - Different FieldToAggregate__c + * - Field value of RelationShipCriteria__c differs by case + * - Effective values for all other fields same differing only by case used + * Should result in Two (2) contexts used, two SOQL for the rollup itself and 3 DML rows (1 for each + * parent - DLRS combines updates to identical master record ids) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleQueryRollupsDifferByOperationFieldAndCaseSameCriteriaDiffCase() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField1 = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateField2 = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Colours__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition.toLowerCase(); + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields.toLowerCase(); + rollupSummaryA.FieldToAggregate__c = aggregateField1.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.First.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField2; + rollupSummaryB.FieldToOrderBy__c = fieldToOrderBy; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField1, 'Red'); + child1.put(aggregateField2, 42); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField1, 'Yellow'); + child2.put(aggregateField2, 15); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField1, 'Blue'); + child3.put(aggregateField2, 10); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup A + // + One query on LookupChild__c for rollup B + System.assertEquals(beforeQueries + 3, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c for rollup A + // + Nine rows for LookupChild__c for rollup B + System.assertEquals(beforeRows + 20, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c for rollup A & B (DLRS combined updates to identical master ids) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals('Blue', (String) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Two similar rollups differing by: + * - Different AggregateOperation__c (both use Query rollup - First/Last) + * - Different AggregateResultField__c + * - Different Order By + * - Effective values for all other fields same differing only by case used + * Should result in Two (2) contexts used, two SOQL for the rollup itself and 3 DML rows (1 for each + * parent - DLRS combines updates to identical master record ids) + **/ + private testmethod static void testLimitsAndContextsUsedMultipleQueryRollupsDifferByOperationFieldCaseOrderBy() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField1 = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateField2 = LookupChild__c.Amount__c.getDescribe().getName(); + String aggregateResultField1 = LookupParent__c.Colours__c.getDescribe().getName(); + String aggregateResultField2 = LookupParent__c.Total2__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + String relationshipCriteriaFields = 'Amount__c'; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummaryA = new LookupRollupSummary__c(); + rollupSummaryA.Name = 'Test Rollup A'; + rollupSummaryA.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummaryA.ChildObject__c = childObjectName.toLowerCase(); + rollupSummaryA.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummaryA.RelationShipCriteria__c = condition; + rollupSummaryA.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryA.FieldToAggregate__c = aggregateField1.toLowerCase(); + rollupSummaryA.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummaryA.AggregateOperation__c = RollupSummaries.AggregateOperation.First.name(); + rollupSummaryA.AggregateResultField__c = aggregateResultField1.toLowerCase(); + rollupSummaryA.Active__c = true; + rollupSummaryA.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryA.CalculationSharingMode__c = sharingMode.toLowerCase(); + + LookupRollupSummary__c rollupSummaryB = new LookupRollupSummary__c(); + rollupSummaryB.Name = 'Test Rollup B'; + rollupSummaryB.ParentObject__c = parentObjectName; + rollupSummaryB.ChildObject__c = childObjectName; + rollupSummaryB.RelationShipField__c = relationshipField; + rollupSummaryB.RelationShipCriteria__c = condition; + rollupSummaryB.RelationShipCriteriaFields__c = relationshipCriteriaFields; + rollupSummaryB.FieldToAggregate__c = aggregateField2; + rollupSummaryB.FieldToOrderBy__c = null; + rollupSummaryB.AggregateOperation__c = RollupSummaries.AggregateOperation.Last.name(); + rollupSummaryB.AggregateResultField__c = aggregateResultField2; + rollupSummaryB.Active__c = true; + rollupSummaryB.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name(); + rollupSummaryB.CalculationSharingMode__c = sharingMode; + + List rollups = new List { rollupSummaryA, rollupSummaryB }; + insert rollups; + + // Insert parents + SObject parentA = parentType.newSObject(); + parentA.put('Name', 'ParentA'); + SObject parentB = parentType.newSObject(); + parentB.put('Name', 'ParentB'); + SObject parentC = parentType.newSObject(); + parentC.put('Name', 'ParentC'); + List parents = new List { parentA, parentB, parentC }; + insert parents; + + // Insert children + List children = new List(); + for(SObject parent : parents) + { + SObject child1 = childType.newSObject(); + child1.put(relationshipField, parent.Id); + child1.put(aggregateField1, 'Red'); + child1.put(aggregateField2, 42); + children.add(child1); + SObject child2 = childType.newSObject(); + child2.put(relationshipField, parent.Id); + child2.put(aggregateField1, 'Yellow'); + child2.put(aggregateField2, 15); + children.add(child2); + SObject child3 = childType.newSObject(); + child3.put(relationshipField, parent.Id); + child3.put(aggregateField1, 'Blue'); + child3.put(aggregateField2, 10); + children.add(child3); + } + + // Sample various limits prior to an update + Integer beforeQueries = Limits.getQueries(); + Integer beforeRows = Limits.getQueryRows(); + Integer beforeDMLRows = Limits.getDMLRows(); + + insert children; + + // Assert limits + // TODO: Remove debug statements - in-place to get full picture when test fails + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); + System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); + + // + One query on Rollup object + // + One query on LookupChild__c for rollup A + // + One query on LookupChild__c for rollup B + System.assertEquals(beforeQueries + 3, Limits.getQueries()); + + // + Two rows for Rollup object + // + Nine rows for LookupChild__c for rollup A + // + Nine rows for LookupChild__c for rollup B + System.assertEquals(beforeRows + 20, Limits.getQueryRows()); + + // + Nine rows for LookupChild__c (from the update statement itself) + // + Three rows for LookupParent__c for rollup A & B (DLRS combined updates to identical master ids) + System.assertEquals(beforeDMLRows + 12, Limits.getDMLRows()); + + // Assert rollups + Map assertParents = new Map(Database.query(String.format('select id, {0}, {1} from {2}', new List{ aggregateResultField1, aggregateResultField2, parentObjectName }))); + System.assertEquals('Blue', (String) assertParents.get(parentA.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentA.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentB.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentB.id).get(aggregateResultField2)); + + System.assertEquals('Blue', (String) assertParents.get(parentC.id).get(aggregateResultField1)); + System.assertEquals(42, (Decimal) assertParents.get(parentC.id).get(aggregateResultField2)); + } + + /** + * Test for issue https://github.com/afawcett/declarative-lookup-rollup-summaries/issues/229 + * Ensure that any field on LookupRollupSummary__c that is describable is updated with describe info + **/ + private testmethod static void testLookupRollupSummaryFieldsMatchDescribeInfo() + { + // Test supported? + if(!TestContext.isSupported()) + return; + + String rollupName = 'Test Rollup'; + Schema.SObjectType parentType = LookupParent__c.sObjectType; + Schema.SObjectType childType = LookupChild__c.sObjectType; + String parentObjectName = parentType.getDescribe().getName(); + String childObjectName = childType.getDescribe().getName(); + String relationshipField = LookupChild__c.LookupParent__c.getDescribe().getName(); + String aggregateField = LookupChild__c.Color__c.getDescribe().getName(); + String aggregateResultField = LookupParent__c.Colours__c.getDescribe().getName(); + String condition = 'Amount__c > 1'; + List relationshipCriteriaFields = new List { 'Amount__c', 'Name', 'Id', 'IsDeleted' }; + String sharingMode = LREngine.SharingMode.User.name(); + String fieldToOrderBy = LookupChild__c.Amount__c.getDescribe().getName(); + + // Configure rollups + LookupRollupSummary__c rollupSummary = new LookupRollupSummary__c(); + rollupSummary.Name = rollupName.toLowerCase(); + rollupSummary.ParentObject__c = parentObjectName.toLowerCase(); + rollupSummary.ChildObject__c = childObjectName.toLowerCase(); + rollupSummary.RelationShipField__c = relationshipField.toLowerCase(); + rollupSummary.RelationShipCriteria__c = condition.toLowerCase(); + rollupSummary.RelationShipCriteriaFields__c = String.join(relationshipCriteriaFields, '\r\n').toLowerCase(); + rollupSummary.FieldToAggregate__c = aggregateField.toLowerCase(); + rollupSummary.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + rollupSummary.AggregateOperation__c = RollupSummaries.AggregateOperation.First.name().toLowerCase(); + rollupSummary.AggregateResultField__c = aggregateResultField.toLowerCase(); + rollupSummary.Active__c = true; + rollupSummary.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name().toLowerCase(); + rollupSummary.CalculationSharingMode__c = sharingMode.toLowerCase(); + insert rollupSummary; + + // Assert field values were updated to describe info + LookupRollupSummary__c assertSummary = [SELECT Name, ParentObject__c, ChildObject__c, RelationshipField__c, RelationShipCriteria__c, RelationShipCriteriaFields__c, + FieldToAggregate__c, FieldToOrderBy__c, AggregateOperation__c, AggregateResultField__c, CalculationMode__c, CalculationSharingMode__c FROM LookupRollupSummary__c WHERE Name = :rollupName]; + + // name & condition are not updated with describe info + System.assertEquals(rollupName.toLowerCase(), assertSummary.Name); + System.assertEquals(condition.toLowerCase(), assertSummary.RelationShipCriteria__c); + + // all remaining fields should match describe + System.assertEquals(parentObjectName, assertSummary.ParentObject__c); + System.assertEquals(childObjectName, assertSummary.ChildObject__c); + System.assertEquals(relationshipField, assertSummary.RelationShipField__c); + System.assertEquals(String.join(relationshipCriteriaFields, '\r\n'), assertSummary.RelationShipCriteriaFields__c); + System.assertEquals(aggregateField, assertSummary.FieldToAggregate__c); + System.assertEquals(fieldToOrderBy, assertSummary.FieldToOrderBy__c); + System.assertEquals(RollupSummaries.AggregateOperation.First.name(), assertSummary.AggregateOperation__c); + System.assertEquals(aggregateResultField, assertSummary.AggregateResultField__c); + System.assertEquals(RollupSummaries.CalculationMode.Realtime.name(), assertSummary.CalculationMode__c); + System.assertEquals(sharingMode, assertSummary.CalculationSharingMode__c); + } } \ No newline at end of file From 023ae41f0219e8c82f589556862a57d5fff5b4eb Mon Sep 17 00:00:00 2001 From: Jon Davis Date: Thu, 20 Aug 2015 00:46:22 -0700 Subject: [PATCH 2/3] Issue #229 - Ensure context is shared when rollups differ by case only Additional debug statements have been removed from tests in this commit. --- rolluptool/src/classes/RollupService.cls | 7 +- rolluptool/src/classes/RollupServiceTest4.cls | 35 ------- rolluptool/src/classes/RollupSummaries.cls | 91 +++++++++++++++++++ 3 files changed, 97 insertions(+), 36 deletions(-) diff --git a/rolluptool/src/classes/RollupService.cls b/rolluptool/src/classes/RollupService.cls index 056a134d..3d710851 100644 --- a/rolluptool/src/classes/RollupService.cls +++ b/rolluptool/src/classes/RollupService.cls @@ -696,7 +696,12 @@ global with sharing class RollupService // Determine if an LREngine Context has been created for this parent child relationship, filter combination or underlying query type and sharing mode? String rsfType = rsf.isAggregateBasedRollup() ? 'aggregate' : 'query'; String orderBy = String.isBlank(Lookup.FieldToOrderBy__c) ? '' : Lookup.FieldToOrderBy__c; - String contextKey = lookup.ParentObject__c + '#' + lookup.RelationshipField__c + '#' + lookup.RelationShipCriteria__c + '#' + rsfType + '#' + sharingMode + '#' + orderBy; + // Lowering case on Describable fields is only required for Legacy purposes since LookupRollupSummary__c records + // will be updated with describe names on insert/update moving forward. + // Ideally this would not be needed to save CPU cycles but including to ensure context is properly re-used when possible for + // rollups that have not been updated/inserted after the insert/update enhancement is applied + // Unable to lower RelationShipCriteria__c because of field value case-(in)sensitivity configuration + String contextKey = lookup.ParentObject__c.toLowerCase() + '#' + lookup.RelationshipField__c.toLowerCase() + '#' + lookup.RelationShipCriteria__c + '#' + rsfType + '#' + sharingMode + '#' + orderBy.toLowerCase(); LREngine.Context lreContext = engineCtxByParentRelationship.get(contextKey); if(lreContext==null) diff --git a/rolluptool/src/classes/RollupServiceTest4.cls b/rolluptool/src/classes/RollupServiceTest4.cls index 3bab5614..924c5786 100644 --- a/rolluptool/src/classes/RollupServiceTest4.cls +++ b/rolluptool/src/classes/RollupServiceTest4.cls @@ -236,11 +236,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup System.assertEquals(beforeQueries + 2, Limits.getQueries()); @@ -363,11 +358,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup A // + One query on LookupChild__c for rollup B @@ -492,11 +482,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup System.assertEquals(beforeQueries + 2, Limits.getQueries()); @@ -619,11 +604,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup A // + One query on LookupChild__c for rollup B @@ -753,11 +733,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup System.assertEquals(beforeQueries + 2, Limits.getQueries()); @@ -886,11 +861,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup A // + One query on LookupChild__c for rollup B @@ -1020,11 +990,6 @@ private class RollupServiceTest4 { insert children; // Assert limits - // TODO: Remove debug statements - in-place to get full picture when test fails - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% Queries - before:{0} after:{1}', new List { String.valueOf(beforeQueries), String.valueOf(Limits.getQueries()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% QueryRows - before:{0} after:{1}', new List { String.valueOf(beforeRows), String.valueOf(Limits.getQueryRows()) })); - System.debug(LoggingLevel.ERROR, String.format('%%LIMITS%% DMLRows - before:{0} after:{1}', new List { String.valueOf(beforeDMLRows), String.valueOf(Limits.getDMLRows()) })); - // + One query on Rollup object // + One query on LookupChild__c for rollup A // + One query on LookupChild__c for rollup B diff --git a/rolluptool/src/classes/RollupSummaries.cls b/rolluptool/src/classes/RollupSummaries.cls index 3ebd2882..1c6ca149 100644 --- a/rolluptool/src/classes/RollupSummaries.cls +++ b/rolluptool/src/classes/RollupSummaries.cls @@ -82,6 +82,97 @@ public class RollupSummaries extends fflib_SObjectDomain { super(records); } + + /** + * Before Insert processing + **/ + public override void onBeforeInsert() + { + updateDescribableFieldNames(); + } + + /** + * Before Update processing + **/ + public override void onBeforeUpdate(Map existingRecords) + { + updateDescribableFieldNames(); + } + + /** + * update field names using describe info + **/ + private void updateDescribableFieldNames() + { + Map gd = Schema.getGlobalDescribe(); + Map> gdFields = new Map>(); + for(LookupRollupSummary__c lookupRollupSummary : (List) Records) + { + SObjectType parentObjectType = gd.get(lookupRollupSummary.ParentObject__c); + SObjectType childObjectType = gd.get(lookupRollupSummary.ChildObject__c); + if(parentObjectType!=null && !gdFields.containsKey(parentObjectType)) + gdFields.put(parentObjectType, parentObjectType.getDescribe().fields.getMap()); + if(childObjectType!=null && !gdFields.containsKey(childObjectType)) + gdFields.put(childObjectType, childObjectType.getDescribe().fields.getMap()); + } + + for(LookupRollupSummary__c lookupRollupSummary : (List) Records) + { + // Parent Object + SObjectType parentObjectType = gd.get(lookupRollupSummary.ParentObject__c); + if(parentObjectType!=null) + lookupRollupSummary.ParentObject__c = parentObjectType.getDescribe().getName(); + + // Child Object + SObjectType childObjectType = gd.get(lookupRollupSummary.ChildObject__c); + if(childObjectType!=null) + lookupRollupSummary.ChildObject__c = childObjectType.getDescribe().getName(); + + // Child Object fields + SObjectField relationshipField = null; + SObjectField fieldToAggregate = null; + SObjectField fieldToOrderBy = null; + Map childObjectFields = gdFields.get(childObjectType); + if(childObjectFields!=null) + { + // Relationship field + relationshipField = childObjectFields.get(lookupRollupSummary.RelationshipField__c); + if(relationshipField!=null) + lookupRollupSummary.RelationshipField__c = relationshipField.getDescribe().getName(); + // Field to Aggregate + fieldToAggregate = childObjectFields.get(lookupRollupSummary.FieldToAggregate__c); + if(fieldToAggregate!=null) + lookupRollupSummary.FieldToAggregate__c = fieldToAggregate.getDescribe().getName(); + // Field to Order By + if(lookupRollupSummary.FieldToOrderBy__c!=null) { + fieldToOrderBy = childObjectFields.get(lookupRollupSummary.FieldToOrderBy__c); + if(fieldToOrderBy!=null) + lookupRollupSummary.FieldToOrderBy__c = fieldToOrderBy.getDescribe().getName(); + } + } + // Parent Object fields + SObjectField aggregateResultField = null; + Map parentObjectFields = gdFields.get(parentObjectType); + if(parentObjectFields!=null) + { + // Aggregate Result field + aggregateResultField = parentObjectFields.get(lookupRollupSummary.AggregateResultField__c); + if(aggregateResultField!=null) + lookupRollupSummary.AggregateResultField__c = aggregateResultField.getDescribe().getName(); + } + // Check the list of fields expressed in the relationship critiera fields + if(childObjectFields!=null && lookupRollupSummary.RelationshipCriteriaFields__c!=null) + { + List relationshipCriteriaFields = new List(); + String[] fieldList = lookupRollupSummary.RelationshipCriteriaFields__c.split('\r\n'); + for(String field : fieldList) { + SObjectField relationshipCriteriaField = childObjectFields.get(field); + relationshipCriteriaFields.add(relationshipCriteriaField !=null ? relationshipCriteriaField.getDescribe().getName() : field); + } + lookupRollupSummary.RelationshipCriteriaFields__c = String.join(relationshipCriteriaFields, '\r\n'); + } + } + } /** * Validations for inserts and updates of records From f0491ceff4c51e7e7757162ce62c4703096fd412 Mon Sep 17 00:00:00 2001 From: Jon Davis Date: Thu, 20 Aug 2015 01:25:16 -0700 Subject: [PATCH 3/3] Issue #229 - Improve test coverage for lookuprollupsummary__c update --- rolluptool/src/classes/RollupServiceTest4.cls | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/rolluptool/src/classes/RollupServiceTest4.cls b/rolluptool/src/classes/RollupServiceTest4.cls index 924c5786..59b6c539 100644 --- a/rolluptool/src/classes/RollupServiceTest4.cls +++ b/rolluptool/src/classes/RollupServiceTest4.cls @@ -1057,23 +1057,59 @@ private class RollupServiceTest4 { insert rollupSummary; // Assert field values were updated to describe info - LookupRollupSummary__c assertSummary = [SELECT Name, ParentObject__c, ChildObject__c, RelationshipField__c, RelationShipCriteria__c, RelationShipCriteriaFields__c, + LookupRollupSummary__c existingSummary = [SELECT Id, Name, ParentObject__c, ChildObject__c, RelationshipField__c, RelationShipCriteria__c, RelationShipCriteriaFields__c, FieldToAggregate__c, FieldToOrderBy__c, AggregateOperation__c, AggregateResultField__c, CalculationMode__c, CalculationSharingMode__c FROM LookupRollupSummary__c WHERE Name = :rollupName]; + // name & condition are not updated with describe info - System.assertEquals(rollupName.toLowerCase(), assertSummary.Name); - System.assertEquals(condition.toLowerCase(), assertSummary.RelationShipCriteria__c); + System.assertEquals(rollupName.toLowerCase(), existingSummary.Name); + System.assertEquals(condition.toLowerCase(), existingSummary.RelationShipCriteria__c); + // all remaining fields should match describe + System.assertEquals(parentObjectName, existingSummary.ParentObject__c); + System.assertEquals(childObjectName, existingSummary.ChildObject__c); + System.assertEquals(relationshipField, existingSummary.RelationShipField__c); + System.assertEquals(String.join(relationshipCriteriaFields, '\r\n'), existingSummary.RelationShipCriteriaFields__c); + System.assertEquals(aggregateField, existingSummary.FieldToAggregate__c); + System.assertEquals(fieldToOrderBy, existingSummary.FieldToOrderBy__c); + System.assertEquals(RollupSummaries.AggregateOperation.First.name(), existingSummary.AggregateOperation__c); + System.assertEquals(aggregateResultField, existingSummary.AggregateResultField__c); + System.assertEquals(RollupSummaries.CalculationMode.Realtime.name(), existingSummary.CalculationMode__c); + System.assertEquals(sharingMode, existingSummary.CalculationSharingMode__c); + + // Set summary values to lowered and update + existingSummary.Name = rollupName.toLowerCase(); + existingSummary.ParentObject__c = parentObjectName.toLowerCase(); + existingSummary.ChildObject__c = childObjectName.toLowerCase(); + existingSummary.RelationShipField__c = relationshipField.toLowerCase(); + existingSummary.RelationShipCriteria__c = condition.toLowerCase(); + existingSummary.RelationShipCriteriaFields__c = String.join(relationshipCriteriaFields, '\r\n').toLowerCase(); + existingSummary.FieldToAggregate__c = aggregateField.toLowerCase(); + existingSummary.FieldToOrderBy__c = fieldToOrderBy.toLowerCase(); + existingSummary.AggregateOperation__c = RollupSummaries.AggregateOperation.First.name().toLowerCase(); + existingSummary.AggregateResultField__c = aggregateResultField.toLowerCase(); + existingSummary.Active__c = true; + existingSummary.CalculationMode__c = RollupSummaries.CalculationMode.Realtime.name().toLowerCase(); + existingSummary.CalculationSharingMode__c = sharingMode.toLowerCase(); + update rollupSummary; + // Assert field values were updated to describe info + existingSummary = [SELECT Id, Name, ParentObject__c, ChildObject__c, RelationshipField__c, RelationShipCriteria__c, RelationShipCriteriaFields__c, + FieldToAggregate__c, FieldToOrderBy__c, AggregateOperation__c, AggregateResultField__c, CalculationMode__c, CalculationSharingMode__c FROM LookupRollupSummary__c WHERE Name = :rollupName]; + + + // name & condition are not updated with describe info + System.assertEquals(rollupName.toLowerCase(), existingSummary.Name); + System.assertEquals(condition.toLowerCase(), existingSummary.RelationShipCriteria__c); // all remaining fields should match describe - System.assertEquals(parentObjectName, assertSummary.ParentObject__c); - System.assertEquals(childObjectName, assertSummary.ChildObject__c); - System.assertEquals(relationshipField, assertSummary.RelationShipField__c); - System.assertEquals(String.join(relationshipCriteriaFields, '\r\n'), assertSummary.RelationShipCriteriaFields__c); - System.assertEquals(aggregateField, assertSummary.FieldToAggregate__c); - System.assertEquals(fieldToOrderBy, assertSummary.FieldToOrderBy__c); - System.assertEquals(RollupSummaries.AggregateOperation.First.name(), assertSummary.AggregateOperation__c); - System.assertEquals(aggregateResultField, assertSummary.AggregateResultField__c); - System.assertEquals(RollupSummaries.CalculationMode.Realtime.name(), assertSummary.CalculationMode__c); - System.assertEquals(sharingMode, assertSummary.CalculationSharingMode__c); + System.assertEquals(parentObjectName, existingSummary.ParentObject__c); + System.assertEquals(childObjectName, existingSummary.ChildObject__c); + System.assertEquals(relationshipField, existingSummary.RelationShipField__c); + System.assertEquals(String.join(relationshipCriteriaFields, '\r\n'), existingSummary.RelationShipCriteriaFields__c); + System.assertEquals(aggregateField, existingSummary.FieldToAggregate__c); + System.assertEquals(fieldToOrderBy, existingSummary.FieldToOrderBy__c); + System.assertEquals(RollupSummaries.AggregateOperation.First.name(), existingSummary.AggregateOperation__c); + System.assertEquals(aggregateResultField, existingSummary.AggregateResultField__c); + System.assertEquals(RollupSummaries.CalculationMode.Realtime.name(), existingSummary.CalculationMode__c); + System.assertEquals(sharingMode, existingSummary.CalculationSharingMode__c); } } \ No newline at end of file