From d3800250ad8acd9e8270db1964ae5e52d4ed36b6 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 20 Sep 2026 12:02:54 +0200 Subject: [PATCH 1/7] Refactoring --- .../main/default/classes/TriggerHandler.cls | 15 +- .../default/classes/TriggerOrchestrator.cls | 46 +- .../classes/TriggerOrchestratorTest.cls | 873 +++++++++++------- 3 files changed, 588 insertions(+), 346 deletions(-) diff --git a/force-app/main/default/classes/TriggerHandler.cls b/force-app/main/default/classes/TriggerHandler.cls index 6ecb8cb..80451df 100644 --- a/force-app/main/default/classes/TriggerHandler.cls +++ b/force-app/main/default/classes/TriggerHandler.cls @@ -304,9 +304,22 @@ public with sharing class TriggerHandler { // Implementation - public static RandomIdGenerator IdGenerator = new RandomIdGenerator(); + @TestVisible + private static RandomIdGenerator IdGenerator = new RandomIdGenerator(); private static RecordTypesInfo RecordTypesInfo = new RecordTypesInfo(); + public static List getTriggerRecordsFrom(List newRecords, List oldRecords) { + List triggerRecords = new List(); + + Integer recordCount = (newRecords ?? oldRecords)?.size() ?? 0; + + for (Integer i = 0; i < recordCount; i++) { + triggerRecords.add(new TriggerRecord(newRecords?.get(i), oldRecords?.get(i))); + } + + return triggerRecords; + } + public class FieldSelector implements FieldSelection { private List fields = new List(); diff --git a/force-app/main/default/classes/TriggerOrchestrator.cls b/force-app/main/default/classes/TriggerOrchestrator.cls index 35c45b6..23ca312 100644 --- a/force-app/main/default/classes/TriggerOrchestrator.cls +++ b/force-app/main/default/classes/TriggerOrchestrator.cls @@ -80,10 +80,8 @@ public with sharing class TriggerOrchestrator { // Implementations - @TestVisible - private static TriggerLogger triggerLogger = new TriggerLogger(); - @TestVisible private static TriggerSettings triggerSettings = new TriggerSettings(); + private static TriggerLogger triggerLogger = new TriggerLogger(); private static TriggerBypass triggerBypass = new TriggerBypass(); private static TriggerStack triggerStack = new TriggerStack(); private static TriggerDepth triggerDepth = new TriggerDepth(); @@ -164,7 +162,6 @@ public with sharing class TriggerOrchestrator { if (this.sObjectType == null) { this.sObjectType = (this.newRecords ?? this.oldRecords)?.getSObjectType(); } - return this.sObjectType; } private set; @@ -173,15 +170,8 @@ public with sharing class TriggerOrchestrator { public List triggerRecords { get { if (this.triggerRecords == null) { - this.triggerRecords = new List(); - - Integer recordCount = (this.newRecords ?? this.oldRecords)?.size() ?? 0; - - for (Integer i = 0; i < recordCount; i++) { - this.triggerRecords.add(new TriggerHandler.TriggerRecord(this.newRecords?.get(i), this.oldRecords?.get(i))); - } + this.triggerRecords = TriggerHandler.getTriggerRecordsFrom(this.newRecords, this.oldRecords); } - return this.triggerRecords; } private set; @@ -189,43 +179,39 @@ public with sharing class TriggerOrchestrator { } private class TriggerBypass implements Bypassable { - private Set bypassedSObjects = new Set(); - private Set bypassedOrchestrators = new Set(); - private Set bypassedHandlers = new Set(); + private Set bypassed = new Set(); public Bypassable sObject(SObjectType sObjectType) { - this.bypassedSObjects.add(sObjectType.toString().toLowerCase()); + this.bypassed.add(sObjectType.toString().toLowerCase()); return this; } public Bypassable orchestrator(System.Type orchestratorType) { - this.bypassedOrchestrators.add(orchestratorType.getName().toLowerCase()); + this.bypassed.add(orchestratorType.getName().toLowerCase()); return this; } public Bypassable handler(System.Type handlerType) { - this.bypassedHandlers.add(handlerType.getName().toLowerCase()); + this.bypassed.add(handlerType.getName().toLowerCase()); return this; } public void all() { - this.bypassedSObjects.add('ALL'); + this.bypassed.add('ALL'); } public void clear() { - this.bypassedSObjects.clear(); - this.bypassedOrchestrators.clear(); - this.bypassedHandlers.clear(); + this.bypassed.clear(); } public Boolean isRunBypassed(TriggerOrchestrator orchestrator) { - return this.bypassedSObjects.contains('ALL') || - this.bypassedSObjects.contains(orchestrator.context.sObjectType?.toString()?.toLowerCase()) || - this.bypassedOrchestrators.contains(orchestrator.orchestrator?.toString()?.substringBefore(':')?.toLowerCase()); + return this.bypassed.contains('ALL') || + this.bypassed.contains(orchestrator.context.sObjectType?.toString()?.toLowerCase()) || + this.bypassed.contains(orchestrator.orchestrator?.toString()?.substringBefore(':')?.toLowerCase()); } public Boolean isHandlerBypassed(String handlerName) { - return this.bypassedHandlers.contains(handlerName.toLowerCase()); + return this.bypassed.contains('ALL') || this.bypassed.contains(handlerName.toLowerCase()); } } @@ -248,7 +234,7 @@ public with sharing class TriggerOrchestrator { private class TriggerDepth { private Map> recursionDepthByRecordByHandler = new Map>(); - public void initForHandler(String recursionScope) { + public void registerScope(String recursionScope) { if (!this.recursionDepthByRecordByHandler.containsKey(recursionScope)) { this.recursionDepthByRecordByHandler.put(recursionScope, new Map()); } @@ -297,7 +283,6 @@ public with sharing class TriggerOrchestrator { @TestVisible private class TriggerSettings { - @TestVisible private Map settingsByObjectName = this.resolveMetadataSettings(); public Boolean isSObjectTriggerBypassed(TriggerContext context) { @@ -308,7 +293,6 @@ public with sharing class TriggerOrchestrator { return this.settingsByObjectName.get(context.sObjectType.toString().toLowerCase())?.settingByHandlerName.get(handlerName.toLowerCase())?.Bypass__c == true; } - @TestVisible private Map resolveMetadataSettings() { Map settingsByObjectName = new Map(); @@ -787,7 +771,7 @@ public with sharing class TriggerOrchestrator { String recursionScope = this.handlerName + ':BEFORE_UPDATE'; - TriggerOrchestrator.triggerDepth.initForHandler(recursionScope); + TriggerOrchestrator.triggerDepth.registerScope(recursionScope); this.recursionDepthByRecord = TriggerOrchestrator.triggerDepth.getForRecursionScope(recursionScope); } @@ -959,7 +943,7 @@ public with sharing class TriggerOrchestrator { super(handler, orchestrator); String recursionScope = this.handlerName + ':AFTER_UPDATE'; - TriggerOrchestrator.triggerDepth.initForHandler(recursionScope); + TriggerOrchestrator.triggerDepth.registerScope(recursionScope); this.recursionDepthByRecord = TriggerOrchestrator.triggerDepth.getForRecursionScope(recursionScope); } diff --git a/force-app/main/default/classes/TriggerOrchestratorTest.cls b/force-app/main/default/classes/TriggerOrchestratorTest.cls index f6c041c..9d5b422 100644 --- a/force-app/main/default/classes/TriggerOrchestratorTest.cls +++ b/force-app/main/default/classes/TriggerOrchestratorTest.cls @@ -21,7 +21,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe', Department = 'Sales'), new Contact(LastName = 'Roe', Department = 'Legal') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -52,7 +53,8 @@ private class TriggerOrchestratorTest { }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -78,7 +80,8 @@ private class TriggerOrchestratorTest { List oldRecords = new List{ new Contact(Id = firstContactId, LastName = 'Old One'), new Contact(Id = secondContactId, LastName = 'Old Two') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -106,7 +109,8 @@ private class TriggerOrchestratorTest { List oldRecords = new List{ new Contact(Id = firstContactId, LastName = 'Old One'), new Contact(Id = secondContactId, LastName = 'Old Two') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -134,7 +138,8 @@ private class TriggerOrchestratorTest { }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -161,7 +166,8 @@ private class TriggerOrchestratorTest { }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -192,7 +198,8 @@ private class TriggerOrchestratorTest { }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -218,7 +225,8 @@ private class TriggerOrchestratorTest { }; DispatchTwoHandlersOrchestrator orchestrator = new DispatchTwoHandlersOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -239,7 +247,8 @@ private class TriggerOrchestratorTest { DispatchPartialOrchestrator orchestrator = new DispatchPartialOrchestrator(); Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -265,7 +274,8 @@ private class TriggerOrchestratorTest { DispatchPartialOrchestrator orchestrator = new DispatchPartialOrchestrator(); Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -289,7 +299,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; DispatchPartialOrchestrator orchestrator = new DispatchPartialOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -309,7 +320,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -332,7 +344,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -355,7 +368,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -447,7 +461,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -473,7 +488,8 @@ private class TriggerOrchestratorTest { DispatchEmptyListOrchestrator orchestrator = new DispatchEmptyListOrchestrator(); Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -500,7 +516,8 @@ private class TriggerOrchestratorTest { DispatchEmptyListOrchestrator orchestrator = new DispatchEmptyListOrchestrator(); Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -525,7 +542,8 @@ private class TriggerOrchestratorTest { List newRecords = new List(); DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -574,9 +592,8 @@ private class TriggerOrchestratorTest { List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old One') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'contact' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = true)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Contact', Bypass__c = true)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -597,9 +614,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'account' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = true)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Account', Bypass__c = true)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -618,9 +634,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(LastName = 'Doe') }; DispatchAllContextsOrchestrator orchestrator = new DispatchAllContextsOrchestrator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'contact' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = false)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Contact', Bypass__c = false)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -642,7 +657,8 @@ private class TriggerOrchestratorTest { orchestrator.handler.logger = logger; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -1242,7 +1258,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler handler = new EnrichmentAfterInsertHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1270,7 +1287,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterUpdateHandler handler = new EnrichmentAfterUpdateHandler(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1295,7 +1313,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler handler = new EnrichmentAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1323,7 +1342,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler handler = new EnrichmentAfterInsertHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1357,7 +1377,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler handler = new EnrichmentAfterInsertHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1395,7 +1416,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler countryHandler = new EnrichmentAfterInsertHandler(); countryHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.BillingCountry)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1442,7 +1464,8 @@ private class TriggerOrchestratorTest { handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); handler.declareNew(Contact.OwnerId, TriggerHandler.FieldSelection.with(User.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1478,7 +1501,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterInsertHandler handler = new EnrichmentAfterInsertHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1512,7 +1536,8 @@ private class TriggerOrchestratorTest { EnrichmentBeforeUpdateHandler readingHandler = new EnrichmentBeforeUpdateHandler(); readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1555,7 +1580,8 @@ private class TriggerOrchestratorTest { EnrichmentBeforeInsertHandler readingHandler = new EnrichmentBeforeInsertHandler(); readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1616,7 +1642,8 @@ private class TriggerOrchestratorTest { EnrichmentBeforeUpdateHandler readingHandler = new EnrichmentBeforeUpdateHandler(); readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1664,7 +1691,8 @@ private class TriggerOrchestratorTest { handlers.add(lastHandler); } - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1710,7 +1738,8 @@ private class TriggerOrchestratorTest { EnrichmentBeforeUpdateHandler readingHandler = new EnrichmentBeforeUpdateHandler(); readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1755,7 +1784,8 @@ private class TriggerOrchestratorTest { readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); readingHandler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1801,7 +1831,8 @@ private class TriggerOrchestratorTest { EnrichmentAfterUpdateHandler readingHandler = new EnrichmentAfterUpdateHandler(); readingHandler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1837,7 +1868,8 @@ private class TriggerOrchestratorTest { handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1871,7 +1903,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertPopulator activeHandler = new BypassBeforeInsertPopulator(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1892,7 +1925,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertPopulator handler = new BypassBeforeInsertPopulator(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1914,7 +1948,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertPopulator activeHandler = new BypassBeforeInsertPopulator(); bypassedValidator.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1936,7 +1971,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertValidator validator = new BypassBeforeInsertValidator(); validator.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1957,7 +1993,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertHandler activeHandler = new BypassAfterInsertHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -1977,7 +2014,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2000,7 +2038,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdatePopulator activeHandler = new BypassBeforeUpdatePopulator(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2024,7 +2063,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdatePopulator handler = new BypassBeforeUpdatePopulator(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2049,7 +2089,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdatePopulator activeHandler = new BypassBeforeUpdatePopulator(); bypassedValidator.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2074,7 +2115,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdateValidator validator = new BypassBeforeUpdateValidator(); validator.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2099,7 +2141,8 @@ private class TriggerOrchestratorTest { BypassAfterUpdateHandler activeHandler = new BypassAfterUpdateHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2123,7 +2166,8 @@ private class TriggerOrchestratorTest { BypassAfterUpdateHandler handler = new BypassAfterUpdateHandler(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2145,7 +2189,8 @@ private class TriggerOrchestratorTest { BypassBeforeDeleteHandler activeHandler = new BypassBeforeDeleteHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2166,7 +2211,8 @@ private class TriggerOrchestratorTest { BypassBeforeDeleteHandler handler = new BypassBeforeDeleteHandler(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2187,7 +2233,8 @@ private class TriggerOrchestratorTest { BypassAfterDeleteHandler activeHandler = new BypassAfterDeleteHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2208,7 +2255,8 @@ private class TriggerOrchestratorTest { BypassAfterDeleteHandler handler = new BypassAfterDeleteHandler(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2228,7 +2276,8 @@ private class TriggerOrchestratorTest { BypassAfterUndeleteHandler activeHandler = new BypassAfterUndeleteHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2248,7 +2297,8 @@ private class TriggerOrchestratorTest { BypassAfterUndeleteHandler handler = new BypassAfterUndeleteHandler(); handler.isBypassed = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2271,7 +2321,8 @@ private class TriggerOrchestratorTest { }; BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2291,7 +2342,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); handler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2313,7 +2365,8 @@ private class TriggerOrchestratorTest { static void handlerWithoutBypassableInterfaceAlwaysRuns() { BypassPlainAfterInsertHandler handler = new BypassPlainAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2333,7 +2386,8 @@ private class TriggerOrchestratorTest { BypassRelatedReaderAfterInsertHandler readerHandler = new BypassRelatedReaderAfterInsertHandler(); bypassedHandler.isBypassed = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2359,7 +2413,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertOrchestrator orchestrator = new BypassAfterInsertOrchestrator(new List()); Exception orchestratorException = null; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2383,10 +2438,14 @@ private class TriggerOrchestratorTest { BypassMetadataHandler bypassedHandler = new BypassMetadataHandler(); BypassAfterInsertHandler activeHandler = new BypassAfterInsertHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = false)); - contactSettings.settingByHandlerName = new Map{ 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "bypassmetadatahandler", "Bypass__c": true}]}, "Bypass__c": false}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2405,10 +2464,14 @@ private class TriggerOrchestratorTest { static void metadataBypassedHandlerIsNeverAskedForItsCodeBypass() { BypassMetadataHandler handler = new BypassMetadataHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2428,10 +2491,14 @@ private class TriggerOrchestratorTest { BypassMetadataPopulator bypassedHandler = new BypassMetadataPopulator(); BypassBeforeInsertPopulator activeHandler = new BypassBeforeInsertPopulator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'bypassmetadatapopulator' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "bypassmetadatapopulator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2453,9 +2520,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertOrchestrator orchestrator = new BypassAfterInsertOrchestrator(new List{ firstHandler, secondHandler }); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'contact' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = true)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Contact', Bypass__c = true)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -2482,9 +2548,8 @@ private class TriggerOrchestratorTest { static void metadataObjectBypassAppliesOnlyToTheNamedObject() { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'account' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = true)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Account', Bypass__c = true)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2502,9 +2567,8 @@ private class TriggerOrchestratorTest { static void metadataObjectRecordWithoutBypassLetsHandlersRun() { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'contact' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = false)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Contact', Bypass__c = false)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2522,13 +2586,14 @@ private class TriggerOrchestratorTest { static void metadataInnerClassQualifiedNameBypassesHandler() { BypassMetadataHandler handler = new BypassMetadataHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ - 'triggerorchestratortest.bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true), - 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) - }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "triggerorchestratortest.bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2546,10 +2611,14 @@ private class TriggerOrchestratorTest { static void metadataInnerClassSimpleNameBypassesHandler() { BypassMetadataHandler handler = new BypassMetadataHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2564,13 +2633,17 @@ private class TriggerOrchestratorTest { } @IsTest - static void metadataQualifiedNameAloneDoesNotBypassInnerClass() { + static void metadataQualifiedNameBypassesInnerClassByEitherSpelling() { BypassMetadataHandler handler = new BypassMetadataHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'triggerorchestratortest.bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "triggerorchestratortest.bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2581,20 +2654,21 @@ private class TriggerOrchestratorTest { Test.stopTest(); // Verify - Assert.areEqual(1, handler.runCount, 'It should be 1.'); + Assert.areEqual(0, handler.runCount, 'It should be 0, because the loader stores a dotted name under both spellings.'); } @IsTest static void metadataNameOfAnotherOuterClassBypassesTheSameSimpleName() { BypassMetadataHandler handler = new BypassMetadataHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ - 'someotherouterclass.bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true), - 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) - }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "someotherouterclass.bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2613,7 +2687,8 @@ private class TriggerOrchestratorTest { BypassMetadataHandler firstHandler = new BypassMetadataHandler(); BypassAfterInsertHandler secondHandler = new BypassAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2629,12 +2704,11 @@ private class TriggerOrchestratorTest { } @IsTest - static void zeroMetadataRecordsLoadWithOneQueryAndBypassNothing() { + static void metadataSettingsAreLoadedOnceAndBypassNothingWhenNoRecordExists() { BypassMetadataHandler handler = new BypassMetadataHandler(); - Integer queriesBeforeLoad = Limits.getQueries(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = TriggerOrchestrator.triggerSettings.resolveMetadataSettings(); - Integer queriesAfterLoad = Limits.getQueries(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2643,16 +2717,12 @@ private class TriggerOrchestratorTest { orchestratorRunner.context.triggerOperation = System.TriggerOperation.AFTER_INSERT; orchestratorRunner.context.newRecords = new List{ new Contact(Id = TriggerHandler.IdGenerator.get(Contact.SObjectType), LastName = 'Bypass') }; orchestratorRunner.run(); - Integer queriesAfterRun = Limits.getQueries(); Test.stopTest(); // Verify - Assert.areEqual(1, queriesAfterLoad - queriesBeforeLoad, 'It should be 1, because the settings load runs one query through the SOQL library.'); - Assert.areEqual(0, queriesAfterRun - queriesBeforeRun, 'It should be 0.'); - Assert.isNotNull(TriggerOrchestrator.triggerSettings.settingsByObjectName, 'It should be not null.'); - Assert.isNull(TriggerOrchestrator.triggerSettings.settingsByObjectName.get('contact'), 'It should be null.'); - Assert.areEqual(1, handler.runCount, 'It should be 1.'); + Assert.areEqual(0, queriesAfterRun - queriesBeforeRun, 'It should be 0, because the settings are loaded once and then read from the cache.'); + Assert.areEqual(1, handler.runCount, 'It should be 1, because no metadata record names the handler.'); } @IsTest @@ -2660,10 +2730,14 @@ private class TriggerOrchestratorTest { BypassMetadataHandler bypassedHandler = new BypassMetadataHandler(); BypassAfterInsertHandler activeHandler = new BypassAfterInsertHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'bypassmetadatahandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "bypassmetadatahandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2687,7 +2761,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2706,7 +2781,8 @@ private class TriggerOrchestratorTest { BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2731,7 +2807,8 @@ private class TriggerOrchestratorTest { }; BypassLastNameAfterInsertHandler handler = new BypassLastNameAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2755,7 +2832,8 @@ private class TriggerOrchestratorTest { }; BypassAfterInsertHandler handler = new BypassAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2776,7 +2854,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertPopulator handler = new BypassBeforeInsertPopulator(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2797,7 +2876,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertPopulator handler = new BypassBeforeInsertPopulator(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2818,7 +2898,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertValidator validator = new BypassBeforeInsertValidator(); validator.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2839,7 +2920,8 @@ private class TriggerOrchestratorTest { BypassBeforeInsertValidator validator = new BypassBeforeInsertValidator(); validator.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2862,7 +2944,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdatePopulator handler = new BypassBeforeUpdatePopulator(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2886,7 +2969,8 @@ private class TriggerOrchestratorTest { BypassBeforeUpdatePopulator handler = new BypassBeforeUpdatePopulator(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2910,7 +2994,8 @@ private class TriggerOrchestratorTest { BypassAfterUpdateHandler handler = new BypassAfterUpdateHandler(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2933,7 +3018,8 @@ private class TriggerOrchestratorTest { BypassAfterUpdateHandler handler = new BypassAfterUpdateHandler(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2955,7 +3041,8 @@ private class TriggerOrchestratorTest { BypassBeforeDeleteHandler handler = new BypassBeforeDeleteHandler(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2975,7 +3062,8 @@ private class TriggerOrchestratorTest { BypassBeforeDeleteHandler handler = new BypassBeforeDeleteHandler(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -2995,7 +3083,8 @@ private class TriggerOrchestratorTest { BypassAfterDeleteHandler handler = new BypassAfterDeleteHandler(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3015,7 +3104,8 @@ private class TriggerOrchestratorTest { BypassAfterDeleteHandler handler = new BypassAfterDeleteHandler(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3034,7 +3124,8 @@ private class TriggerOrchestratorTest { BypassAfterUndeleteHandler handler = new BypassAfterUndeleteHandler(); handler.isQualified = true; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3053,7 +3144,8 @@ private class TriggerOrchestratorTest { BypassAfterUndeleteHandler handler = new BypassAfterUndeleteHandler(); handler.isQualified = false; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3073,7 +3165,8 @@ private class TriggerOrchestratorTest { BypassTitlePopulator firstHandler = new BypassTitlePopulator(); BypassTitleReaderPopulator secondHandler = new BypassTitleReaderPopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3095,7 +3188,8 @@ private class TriggerOrchestratorTest { BypassTitleReaderPopulator firstHandler = new BypassTitleReaderPopulator(); BypassTitlePopulator secondHandler = new BypassTitlePopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3117,9 +3211,8 @@ private class TriggerOrchestratorTest { BypassNestedRunHandler handler = new BypassNestedRunHandler(); TriggerOrchestrator.triggerLogger.logger = loggerStub; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ - 'account' => new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt(Bypass__c = true)) - }; + SOQL.mock('TriggerObject__mdt').thenReturn(new TriggerObject__mdt(ObjectAPIName__c = 'Account', Bypass__c = true)); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -3141,7 +3234,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBeforeUpdateHandler handler = new RecursionBeforeUpdateHandler(); @@ -3166,7 +3260,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterUpdateHandler handler = new RecursionAfterUpdateHandler(); @@ -3191,7 +3286,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedBeforeUpdateHandler handler = new RecursionGuardedBeforeUpdateHandler(2); @@ -3216,7 +3312,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedAfterUpdateHandler handler = new RecursionGuardedAfterUpdateHandler(2); @@ -3241,7 +3338,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBeforeUpdateHandler firstHandler = new RecursionBeforeUpdateHandler(); RecursionSecondBeforeUpdateHandler secondHandler = new RecursionSecondBeforeUpdateHandler(); @@ -3270,7 +3368,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterUpdateHandler firstHandler = new RecursionAfterUpdateHandler(); RecursionSecondAfterUpdateHandler secondHandler = new RecursionSecondAfterUpdateHandler(); @@ -3299,7 +3398,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedBeforeUpdateHandler guardedHandler = new RecursionGuardedBeforeUpdateHandler(2); RecursionBeforeUpdateHandler unguardedHandler = new RecursionBeforeUpdateHandler(); @@ -3332,7 +3432,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedAfterUpdateHandler guardedHandler = new RecursionGuardedAfterUpdateHandler(2); RecursionAfterUpdateHandler unguardedHandler = new RecursionAfterUpdateHandler(); @@ -3365,7 +3466,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBeforeUpdateHandler firstHandler = new RecursionBeforeUpdateHandler(); RecursionSecondBeforeUpdateHandler secondHandler = new RecursionSecondBeforeUpdateHandler(); @@ -3393,7 +3495,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterUpdateHandler firstHandler = new RecursionAfterUpdateHandler(); RecursionSecondAfterUpdateHandler secondHandler = new RecursionSecondAfterUpdateHandler(); @@ -3422,7 +3525,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = firstContactId, LastName = 'Ada'), new Contact(Id = secondContactId, LastName = 'Bob') }; List oldRecords = new List{ new Contact(Id = firstContactId, LastName = 'Ada'), new Contact(Id = secondContactId, LastName = 'Bob') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedBeforeUpdateHandler handler = new RecursionGuardedBeforeUpdateHandler(2); @@ -3450,7 +3554,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = firstContactId, LastName = 'Ada'), new Contact(Id = secondContactId, LastName = 'Bob') }; List oldRecords = new List{ new Contact(Id = firstContactId, LastName = 'Ada'), new Contact(Id = secondContactId, LastName = 'Bob') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedAfterUpdateHandler handler = new RecursionGuardedAfterUpdateHandler(2); @@ -3478,7 +3583,8 @@ private class TriggerOrchestratorTest { Contact exhaustedContact = new Contact(Id = exhaustedContactId, LastName = 'Ada'); Contact lateContact = new Contact(Id = lateContactId, LastName = 'Bob'); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedAfterUpdateHandler handler = new RecursionGuardedAfterUpdateHandler(2); RecursionAfterUpdateOrchestrator orchestrator = new RecursionAfterUpdateOrchestrator(new List{ handler }); @@ -3517,7 +3623,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ qualifiedContact, rejectedContact }; List oldRecords = new List{ qualifiedContact.clone(true), rejectedContact.clone(true) }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionSelectiveBeforeUpdateHandler handler = new RecursionSelectiveBeforeUpdateHandler(); RecursionBeforeUpdateOrchestrator orchestrator = new RecursionBeforeUpdateOrchestrator(new List{ handler }); @@ -3557,7 +3664,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ qualifiedContact, rejectedContact }; List oldRecords = new List{ qualifiedContact.clone(true), rejectedContact.clone(true) }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionSelectiveAfterUpdateHandler handler = new RecursionSelectiveAfterUpdateHandler(); RecursionAfterUpdateOrchestrator orchestrator = new RecursionAfterUpdateOrchestrator(new List{ handler }); @@ -3595,7 +3703,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ qualifiedContact, rejectedContact }; List oldRecords = new List{ qualifiedContact.clone(true), rejectedContact.clone(true) }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionSelectiveAfterUpdateHandler handler = new RecursionSelectiveAfterUpdateHandler(); @@ -3620,7 +3729,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedBeforeUpdateHandler guardedHandler = new RecursionGuardedBeforeUpdateHandler(1); RecursionBeforeUpdateHandler unguardedHandler = new RecursionBeforeUpdateHandler(); @@ -3649,7 +3759,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedAfterUpdateHandler guardedHandler = new RecursionGuardedAfterUpdateHandler(1); RecursionAfterUpdateHandler unguardedHandler = new RecursionAfterUpdateHandler(); @@ -3678,7 +3789,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBothUpdatesHandler handler = new RecursionBothUpdatesHandler(); RecursionBothUpdatesOrchestrator orchestrator = new RecursionBothUpdatesOrchestrator(handler); @@ -3713,7 +3825,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionLogger logger = new RecursionLogger(); @@ -3750,7 +3863,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionLogger logger = new RecursionLogger(); @@ -3787,7 +3901,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionFinalizingAfterUpdateHandler handler = new RecursionFinalizingAfterUpdateHandler(1); @@ -3813,7 +3928,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterUpdateHandler firstInstance = new RecursionAfterUpdateHandler(); RecursionAfterUpdateHandler secondInstance = new RecursionAfterUpdateHandler(); @@ -3847,7 +3963,8 @@ private class TriggerOrchestratorTest { oldRecords.add(new Contact(Id = contactId, LastName = 'Ada')); } - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBeforeUpdateHandler handler = new RecursionBeforeUpdateHandler(); @@ -3879,7 +3996,8 @@ private class TriggerOrchestratorTest { oldRecords.add(new Contact(Id = contactId, LastName = 'Ada')); } - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterUpdateHandler handler = new RecursionAfterUpdateHandler(); @@ -3903,7 +4021,8 @@ private class TriggerOrchestratorTest { static void recursionGuardDoesNotApplyToAfterInsert() { List newRecords = new List{ new Contact(Id = TriggerHandler.IdGenerator.get(Contact.SObjectType), LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionAfterInsertHandler handler = new RecursionAfterInsertHandler(); @@ -3927,7 +4046,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionBeforeUpdateValidator handler = new RecursionBeforeUpdateValidator(); @@ -3952,7 +4072,8 @@ private class TriggerOrchestratorTest { List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); RecursionGuardedBeforeUpdateValidator handler = new RecursionGuardedBeforeUpdateValidator(2); @@ -3977,7 +4098,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingMutedFailingHandler failingHandler = new ErrorsLoggingMutedFailingHandler(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4009,7 +4131,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingMutedFailingHandler failingHandler = new ErrorsLoggingMutedFailingHandler(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4030,7 +4153,8 @@ private class TriggerOrchestratorTest { static void continueOnErrorLogsEveryFailingHandler() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4055,7 +4179,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingFailingHandler failingHandler = new ErrorsLoggingFailingHandler(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4085,7 +4210,8 @@ private class TriggerOrchestratorTest { static void handlerWithoutContinueOnErrorPropagatesItsOwnExceptionType() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4112,7 +4238,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesContinueOnErrorFailureWithHandlerNameAndOperation() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4136,7 +4263,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesUncaughtErrorBeforeItPropagates() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4169,7 +4297,8 @@ private class TriggerOrchestratorTest { List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4198,7 +4327,8 @@ private class TriggerOrchestratorTest { List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Deleted') }; ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4222,7 +4352,8 @@ private class TriggerOrchestratorTest { static void loggerErrorCarriesNoRecordIdsInBeforeInsert() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4252,7 +4383,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesErrorFromQualificationPredicate() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4282,7 +4414,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesErrorFromFinalizer() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4317,7 +4450,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); ErrorsLoggingCountingHandler handler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4338,7 +4472,8 @@ private class TriggerOrchestratorTest { static void loggerFinalizeRunsOnceOnAFailedInvocation() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4367,7 +4502,8 @@ private class TriggerOrchestratorTest { List records = new List{ new Contact(LastName = 'Chunk') }; ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4399,7 +4535,8 @@ private class TriggerOrchestratorTest { logger ); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4421,7 +4558,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); ErrorsLoggingNestedRunHandler outerHandler = new ErrorsLoggingNestedRunHandler(new ErrorsLoggingNoInterfaceOrchestrator(), logger); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4442,7 +4580,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); ErrorsLoggingCountingPopulator laterHandler = new ErrorsLoggingCountingPopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4475,7 +4614,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesFrameworkGuardViolationBeforeItPropagates() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4515,7 +4655,8 @@ private class TriggerOrchestratorTest { new ErrorsLoggingBeforeInsertOrchestrator(new List{ new ErrorsLoggingMutedRecordApiPopulator() }) ); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4552,7 +4693,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; TriggerHandler.TriggerHandlerException recordApiException = null; @@ -4581,7 +4723,8 @@ private class TriggerOrchestratorTest { static void loggerReceivesTriggerHandlerExceptionBeforeItPropagates() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4611,7 +4754,8 @@ private class TriggerOrchestratorTest { static void platformBadCastPropagatesUnchanged() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4640,7 +4784,8 @@ private class TriggerOrchestratorTest { static void platformNullDereferencePropagatesUnchanged() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4670,7 +4815,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; // Test @@ -4693,7 +4839,8 @@ private class TriggerOrchestratorTest { static void emptyHandlerListRunsNothing() { ErrorsLoggingLogger logger = new ErrorsLoggingLogger(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = logger; Exception orchestratorException = null; @@ -4718,7 +4865,8 @@ private class TriggerOrchestratorTest { @IsTest static void withoutALoggerAFailureStillPropagates() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = null; Exception orchestratorException = null; @@ -4747,7 +4895,8 @@ private class TriggerOrchestratorTest { ErrorsLoggingMutedFailingHandler failingHandler = new ErrorsLoggingMutedFailingHandler(); ErrorsLoggingCountingHandler laterHandler = new ErrorsLoggingCountingHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); TriggerOrchestrator.triggerLogger.logger = null; // Test @@ -4765,7 +4914,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertPopulatorPerformingDmlThrows() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -4792,7 +4942,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertValidatorPerformingDmlThrows() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -4818,7 +4969,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertFinalizerPerformingDmlThrows() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertFinalizer handler = new DmlGuardInsertFinalizer(); Exception orchestratorException = null; @@ -4846,7 +4998,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertQualificationPerformingDmlThrows() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertQualifier handler = new DmlGuardInsertQualifier(); Exception orchestratorException = null; @@ -4874,7 +5027,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertDmlBelowTheHandlerThrows() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -4901,7 +5055,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertWithoutDmlDoesNotThrow() { List records = new List{ new Contact(LastName = 'Guard') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertSilentPopulator handler = new DmlGuardInsertSilentPopulator(); Exception orchestratorException = null; @@ -4925,7 +5080,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertGuardNamesTheHandlerThatPerformedDml() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertSilentPopulator cleanHandler = new DmlGuardInsertSilentPopulator(); Exception orchestratorException = null; @@ -4955,7 +5111,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertContinueOnErrorDoesNotSuppressGuard() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertSilentPopulator laterHandler = new DmlGuardInsertSilentPopulator(); Exception orchestratorException = null; @@ -4985,7 +5142,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertGuardSurvivesHandlerException() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5011,7 +5169,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeInsertHandlerExceptionWithoutDmlStaysSilent() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardInsertContinueFailingPopulator handler = new DmlGuardInsertContinueFailingPopulator(); Exception orchestratorException = null; @@ -5037,7 +5196,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5067,7 +5227,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5097,7 +5258,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardUpdateFinalizer handler = new DmlGuardUpdateFinalizer(); Exception orchestratorException = null; @@ -5129,7 +5291,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardUpdateQualifier handler = new DmlGuardUpdateQualifier(); Exception orchestratorException = null; @@ -5163,7 +5326,8 @@ private class TriggerOrchestratorTest { insert existingAccount; List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5193,7 +5357,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardUpdateSilentPopulator handler = new DmlGuardUpdateSilentPopulator(); Exception orchestratorException = null; @@ -5221,7 +5386,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardUpdateSilentPopulator laterHandler = new DmlGuardUpdateSilentPopulator(); Exception orchestratorException = null; @@ -5255,7 +5421,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5285,7 +5452,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardUpdateContinueFailingPopulator handler = new DmlGuardUpdateContinueFailingPopulator(); Exception orchestratorException = null; @@ -5309,7 +5477,8 @@ private class TriggerOrchestratorTest { @IsTest static void afterInsertHandlerPerformingDmlIsAllowed() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5331,7 +5500,8 @@ private class TriggerOrchestratorTest { @IsTest static void afterInsertFinalizerPerformingDmlIsAllowed() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); DmlGuardAfterInsertFinalizer handler = new DmlGuardAfterInsertFinalizer(); Exception orchestratorException = null; @@ -5359,7 +5529,8 @@ private class TriggerOrchestratorTest { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5383,7 +5554,8 @@ private class TriggerOrchestratorTest { @IsTest static void afterDeleteHandlerPerformingDmlIsAllowed() { List oldRecords = new List{ new Contact(Id = TriggerHandler.IdGenerator.get(Contact.SObjectType), LastName = 'Deleted') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5405,7 +5577,8 @@ private class TriggerOrchestratorTest { @IsTest static void afterUndeleteHandlerPerformingDmlIsAllowed() { - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -5428,7 +5601,8 @@ private class TriggerOrchestratorTest { @IsTest static void beforeDeleteHandlerPerformingDmlIsAllowed() { List oldRecords = new List{ new Contact(Id = TriggerHandler.IdGenerator.get(Contact.SObjectType), LastName = 'Deleted') }; - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; // Test @@ -6386,10 +6560,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedInsertPopulator mutedPopulator = new GapMetadataBypassMutedInsertPopulator(); GapMetadataBypassLiveInsertPopulator livePopulator = new GapMetadataBypassLiveInsertPopulator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedinsertpopulator' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedinsertpopulator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6413,10 +6591,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedInsertValidator mutedValidator = new GapMetadataBypassMutedInsertValidator(); GapMetadataBypassLiveInsertValidator liveValidator = new GapMetadataBypassLiveInsertValidator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedinsertvalidator' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedinsertvalidator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6441,10 +6623,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedAfterInsertHandler mutedHandler = new GapMetadataBypassMutedAfterInsertHandler(); GapMetadataBypassLiveAfterInsertHandler liveHandler = new GapMetadataBypassLiveAfterInsertHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedafterinserthandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedafterinserthandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6468,10 +6654,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedUpdatePopulator mutedPopulator = new GapMetadataBypassMutedUpdatePopulator(); GapMetadataBypassLiveUpdatePopulator livePopulator = new GapMetadataBypassLiveUpdatePopulator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedupdatepopulator' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedupdatepopulator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6498,10 +6688,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedUpdateValidator mutedValidator = new GapMetadataBypassMutedUpdateValidator(); GapMetadataBypassLiveUpdateValidator liveValidator = new GapMetadataBypassLiveUpdateValidator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedupdatevalidator' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedupdatevalidator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6530,10 +6724,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedAfterUpdateHandler mutedHandler = new GapMetadataBypassMutedAfterUpdateHandler(); GapMetadataBypassLiveAfterUpdateHandler liveHandler = new GapMetadataBypassLiveAfterUpdateHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedafterupdatehandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedafterupdatehandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6556,10 +6754,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedBeforeDeleteHandler mutedHandler = new GapMetadataBypassMutedBeforeDeleteHandler(); GapMetadataBypassLiveBeforeDeleteHandler liveHandler = new GapMetadataBypassLiveBeforeDeleteHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedbeforedeletehandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedbeforedeletehandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6583,10 +6785,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedAfterDeleteHandler mutedHandler = new GapMetadataBypassMutedAfterDeleteHandler(); GapMetadataBypassLiveAfterDeleteHandler liveHandler = new GapMetadataBypassLiveAfterDeleteHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedafterdeletehandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedafterdeletehandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6607,10 +6813,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassMutedAfterUndeleteHandler mutedHandler = new GapMetadataBypassMutedAfterUndeleteHandler(); GapMetadataBypassLiveAfterUndeleteHandler liveHandler = new GapMetadataBypassLiveAfterUndeleteHandler(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ 'gapmetadatabypassmutedafterundeletehandler' => new TriggerHandler__mdt(Bypass__c = true) }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "gapmetadatabypassmutedafterundeletehandler", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6636,13 +6846,14 @@ private class TriggerOrchestratorTest { GapMetadataBypassDottedNameValidator dottedValidator = new GapMetadataBypassDottedNameValidator(); GapMetadataBypassLiveUpdateValidator liveValidator = new GapMetadataBypassLiveUpdateValidator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ - 'triggerorchestratortest.gapmetadatabypassdottednamevalidator' => new TriggerHandler__mdt(Bypass__c = true), - 'gapmetadatabypassdottednamevalidator' => new TriggerHandler__mdt(Bypass__c = true) - }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "triggerorchestratortest.gapmetadatabypassdottednamevalidator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6661,18 +6872,20 @@ private class TriggerOrchestratorTest { } @IsTest - static void gapMetadataBypassDottedEntryWithoutTailRunsBeforeUpdateValidator() { + static void gapMetadataBypassDottedEntryStopsBeforeUpdateValidator() { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); List newRecords = new List{ new Contact(Id = contactId, LastName = 'New') }; List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Old') }; GapMetadataBypassDottedNameValidator dottedValidator = new GapMetadataBypassDottedNameValidator(); - TriggerOrchestrator.MetadataSettings contactSettings = new TriggerOrchestrator.MetadataSettings(new TriggerObject__mdt()); - contactSettings.settingByHandlerName = new Map{ - 'triggerorchestratortest.gapmetadatabypassdottednamevalidator' => new TriggerHandler__mdt(Bypass__c = true) - }; - - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map{ 'contact' => contactSettings }; + SOQL.mock('TriggerObject__mdt') + .thenReturn( + (TriggerObject__mdt) JSON.deserialize( + '{"ObjectAPIName__c": "Contact", "TriggerHandlers__r": {"totalSize": 1, "done": true, "records": [{"attributes": {"type": "TriggerHandler__mdt"}, "ApexClassName__c": "triggerorchestratortest.gapmetadatabypassdottednamevalidator", "Bypass__c": true}]}}', + TriggerObject__mdt.class + ) + ); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6684,7 +6897,7 @@ private class TriggerOrchestratorTest { Test.stopTest(); // Verify - Assert.areEqual(1, dottedValidator.messageCount, 'It should be 1.'); + Assert.areEqual(0, dottedValidator.messageCount, 'It should be 0, because the loader stores a dotted name under both spellings.'); } @IsTest @@ -6697,7 +6910,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeInsertPopulator handler = new GapEnrichmentBeforeInsertPopulator(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6722,7 +6936,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeInsertValidator handler = new GapEnrichmentBeforeInsertValidator(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6754,7 +6969,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeInsertValidator validator = new GapEnrichmentBeforeInsertValidator(); validator.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6797,7 +7013,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeUpdatePopulator handler = new GapEnrichmentBeforeUpdatePopulator(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6825,7 +7042,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeUpdatePopulator handler = new GapEnrichmentBeforeUpdatePopulator(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6854,7 +7072,8 @@ private class TriggerOrchestratorTest { handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6894,7 +7113,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeUpdateValidator handler = new GapEnrichmentBeforeUpdateValidator(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6922,7 +7142,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeUpdateValidator handler = new GapEnrichmentBeforeUpdateValidator(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6948,7 +7169,8 @@ private class TriggerOrchestratorTest { GapEnrichmentAfterInsertHandler handler = new GapEnrichmentAfterInsertHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -6975,7 +7197,8 @@ private class TriggerOrchestratorTest { GapEnrichmentAfterUpdateHandler handler = new GapEnrichmentAfterUpdateHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -7003,7 +7226,8 @@ private class TriggerOrchestratorTest { GapEnrichmentAfterUpdateHandler handler = new GapEnrichmentAfterUpdateHandler(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -7029,7 +7253,8 @@ private class TriggerOrchestratorTest { GapEnrichmentBeforeDeleteHandler handler = new GapEnrichmentBeforeDeleteHandler(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -7054,7 +7279,8 @@ private class TriggerOrchestratorTest { GapEnrichmentAfterDeleteHandler handler = new GapEnrichmentAfterDeleteHandler(); handler.declareOld(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -7079,7 +7305,8 @@ private class TriggerOrchestratorTest { GapEnrichmentAfterUndeleteHandler handler = new GapEnrichmentAfterUndeleteHandler(); handler.declareNew(Contact.AccountId, TriggerHandler.FieldSelection.with(Account.Name)); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); // Test Test.startTest(); @@ -7099,7 +7326,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedBeforeInsertPopulator failingPopulator = new GapContinueOnErrorMutedBeforeInsertPopulator(); GapContinueOnErrorCountingBeforeInsertPopulator laterPopulator = new GapContinueOnErrorCountingBeforeInsertPopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7128,7 +7356,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingBeforeInsertPopulator failingPopulator = new GapContinueOnErrorFailingBeforeInsertPopulator(); GapContinueOnErrorCountingBeforeInsertPopulator laterPopulator = new GapContinueOnErrorCountingBeforeInsertPopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7159,7 +7388,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedBeforeInsertValidator failingValidator = new GapContinueOnErrorMutedBeforeInsertValidator(); GapContinueOnErrorCountingBeforeInsertValidator laterValidator = new GapContinueOnErrorCountingBeforeInsertValidator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7190,7 +7420,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingBeforeInsertValidator failingValidator = new GapContinueOnErrorFailingBeforeInsertValidator(); GapContinueOnErrorCountingBeforeInsertValidator laterValidator = new GapContinueOnErrorCountingBeforeInsertValidator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7221,7 +7452,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedAfterInsertHandler failingHandler = new GapContinueOnErrorMutedAfterInsertHandler(); GapContinueOnErrorCountingAfterInsertHandler laterHandler = new GapContinueOnErrorCountingAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7250,7 +7482,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingAfterInsertHandler failingHandler = new GapContinueOnErrorFailingAfterInsertHandler(); GapContinueOnErrorCountingAfterInsertHandler laterHandler = new GapContinueOnErrorCountingAfterInsertHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7283,7 +7516,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedBeforeUpdatePopulator failingPopulator = new GapContinueOnErrorMutedBeforeUpdatePopulator(); GapContinueOnErrorCountingBeforeUpdatePopulator laterPopulator = new GapContinueOnErrorCountingBeforeUpdatePopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7316,7 +7550,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingBeforeUpdatePopulator failingPopulator = new GapContinueOnErrorFailingBeforeUpdatePopulator(); GapContinueOnErrorCountingBeforeUpdatePopulator laterPopulator = new GapContinueOnErrorCountingBeforeUpdatePopulator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7350,7 +7585,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedBeforeUpdateValidator failingValidator = new GapContinueOnErrorMutedBeforeUpdateValidator(); GapContinueOnErrorCountingBeforeUpdateValidator laterValidator = new GapContinueOnErrorCountingBeforeUpdateValidator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7384,7 +7620,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingBeforeUpdateValidator failingValidator = new GapContinueOnErrorFailingBeforeUpdateValidator(); GapContinueOnErrorCountingBeforeUpdateValidator laterValidator = new GapContinueOnErrorCountingBeforeUpdateValidator(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7419,7 +7656,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedAfterUpdateHandler failingHandler = new GapContinueOnErrorMutedAfterUpdateHandler(); GapContinueOnErrorCountingAfterUpdateHandler laterHandler = new GapContinueOnErrorCountingAfterUpdateHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7452,7 +7690,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingAfterUpdateHandler failingHandler = new GapContinueOnErrorFailingAfterUpdateHandler(); GapContinueOnErrorCountingAfterUpdateHandler laterHandler = new GapContinueOnErrorCountingAfterUpdateHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7484,7 +7723,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedBeforeDeleteHandler failingHandler = new GapContinueOnErrorMutedBeforeDeleteHandler(); GapContinueOnErrorCountingBeforeDeleteHandler laterHandler = new GapContinueOnErrorCountingBeforeDeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7514,7 +7754,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingBeforeDeleteHandler failingHandler = new GapContinueOnErrorFailingBeforeDeleteHandler(); GapContinueOnErrorCountingBeforeDeleteHandler laterHandler = new GapContinueOnErrorCountingBeforeDeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7545,7 +7786,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedAfterDeleteHandler failingHandler = new GapContinueOnErrorMutedAfterDeleteHandler(); GapContinueOnErrorCountingAfterDeleteHandler laterHandler = new GapContinueOnErrorCountingAfterDeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7575,7 +7817,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingAfterDeleteHandler failingHandler = new GapContinueOnErrorFailingAfterDeleteHandler(); GapContinueOnErrorCountingAfterDeleteHandler laterHandler = new GapContinueOnErrorCountingAfterDeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7605,7 +7848,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorMutedAfterUndeleteHandler failingHandler = new GapContinueOnErrorMutedAfterUndeleteHandler(); GapContinueOnErrorCountingAfterUndeleteHandler laterHandler = new GapContinueOnErrorCountingAfterUndeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; @@ -7634,7 +7878,8 @@ private class TriggerOrchestratorTest { GapContinueOnErrorFailingAfterUndeleteHandler failingHandler = new GapContinueOnErrorFailingAfterUndeleteHandler(); GapContinueOnErrorCountingAfterUndeleteHandler laterHandler = new GapContinueOnErrorCountingAfterUndeleteHandler(); - TriggerOrchestrator.triggerSettings.settingsByObjectName = new Map(); + SOQL.mock('TriggerObject__mdt').thenReturn(new List()); + SOQL.mock('ApexTypeImplementor').thenReturn(new List()); Exception orchestratorException = null; From f2aaf6d97939c8b20f847fe2f2051f54ec2e16b9 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 20 Sep 2026 13:54:48 +0200 Subject: [PATCH 2/7] Refactor --- .../default/classes/TriggerOrchestrator.cls | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/force-app/main/default/classes/TriggerOrchestrator.cls b/force-app/main/default/classes/TriggerOrchestrator.cls index 23ca312..83d8384 100644 --- a/force-app/main/default/classes/TriggerOrchestrator.cls +++ b/force-app/main/default/classes/TriggerOrchestrator.cls @@ -89,11 +89,13 @@ public with sharing class TriggerOrchestrator { @TestVisible private TriggerContext context; private Object orchestrator; + private LookupEnrichment lookupEnrichment; @TestVisible private TriggerOrchestrator(Object orchestrator) { this.orchestrator = orchestrator; this.context = new TriggerContext(); + this.lookupEnrichment = new LookupEnrichment(this.context.triggerRecords); } @TestVisible @@ -340,22 +342,18 @@ public with sharing class TriggerOrchestrator { private abstract class ExecutionStrategy { public void execute(TriggerOrchestrator orchestrator) { - List triggerRecords = orchestrator.context.triggerRecords; List activeHandlers = this.getActiveHandlers(orchestrator); - ParentRelationshipEnrichment parentRelationshipEnrichment = new ParentRelationshipEnrichment(); - - parentRelationshipEnrichment.extractFieldsToEnrich(activeHandlers); - parentRelationshipEnrichment.enrichRecordsLookups(triggerRecords); + orchestrator.lookupEnrichment.queryParentRelationships(activeHandlers); for (TriggerHandlerAdapter adapter : activeHandlers) { try { - adapter.execute(triggerRecords); + adapter.execute(orchestrator.context.triggerRecords); } catch (Exception e) { adapter.handleException(e); } - this.requeryChangedParentLookups(parentRelationshipEnrichment, adapter.getProcessedRecords()); + orchestrator.lookupEnrichment.requeryWhenParentLookupChanged(adapter.getProcessedRecords()); } } @@ -372,16 +370,9 @@ public with sharing class TriggerOrchestrator { } protected abstract List adaptHandlers(TriggerOrchestrator orchestrator); - - protected virtual void requeryChangedParentLookups(ParentRelationshipEnrichment parentRelationshipEnrichment, List records) { - } } private class BeforeInsertExecutionStrategy extends ExecutionStrategy { - protected override void requeryChangedParentLookups(ParentRelationshipEnrichment parentRelationshipEnrichment, List records) { - parentRelationshipEnrichment.requeryWhenParentLookupChanged(records); - } - public override List adaptHandlers(TriggerOrchestrator orchestrator) { List handlerAdapters = new List(); @@ -410,10 +401,6 @@ public with sharing class TriggerOrchestrator { } private class BeforeUpdateExecutionStrategy extends ExecutionStrategy { - protected override void requeryChangedParentLookups(ParentRelationshipEnrichment parentRelationshipEnrichment, List records) { - parentRelationshipEnrichment.requeryWhenParentLookupChanged(records); - } - public override List adaptHandlers(TriggerOrchestrator orchestrator) { List handlerAdapters = new List(); @@ -1149,14 +1136,25 @@ public with sharing class TriggerOrchestrator { } } - private class ParentRelationshipEnrichment { + private class LookupEnrichment { private Set newParentLookupsToEnrich = new Set(); private Set oldParentLookupsToEnrich = new Set(); private Map> fieldsToQueryByParentLookup = new Map>(); private Map> cachedParentByParentLookup = new Map>(); - public void extractFieldsToEnrich(List handlers) { + private List triggerRecords; + + public LookupEnrichment(List triggerRecords) { + this.triggerRecords = triggerRecords; + } + + public void queryParentRelationships(List handlers) { + this.extractFieldsToEnrichList(handlers); + this.enrichRecordsLookups(); + } + + private void extractFieldsToEnrichList(List handlers) { for (TriggerHandlerAdapter handler : handlers) { if (handler instanceof NewRecordEnricher) { this.declareNewFieldsToEnrich(((NewRecordEnricher) handler).getNewFieldsToEnrich()); @@ -1167,17 +1165,17 @@ public with sharing class TriggerOrchestrator { } } - public void enrichRecordsLookups(List records) { + private void enrichRecordsLookups() { for (SObjectField parentField : this.fieldsToQueryByParentLookup.keySet()) { Set parentIdsToQuery = new Set(); - parentIdsToQuery.addAll(this.notQueriedNewParentIds(parentField, records)); - parentIdsToQuery.addAll(this.notQueriedOldParentIds(parentField, records)); + parentIdsToQuery.addAll(this.notQueriedNewParentIds(parentField, this.triggerRecords)); + parentIdsToQuery.addAll(this.notQueriedOldParentIds(parentField, this.triggerRecords)); this.queryParentsRelationships(parentField, parentIdsToQuery); - this.attachNewToTriggerRecords(parentField, records); - this.attachOldToTriggerRecords(parentField, records); + this.attachNewToTriggerRecords(parentField, this.triggerRecords); + this.attachOldToTriggerRecords(parentField, this.triggerRecords); } } From 8e63e2eac2267e00bd29f1b32db61b8172616352 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 20 Sep 2026 20:51:17 +0200 Subject: [PATCH 3/7] Refactoring --- .../default/classes/TriggerOrchestrator.cls | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/force-app/main/default/classes/TriggerOrchestrator.cls b/force-app/main/default/classes/TriggerOrchestrator.cls index 83d8384..c9d31a8 100644 --- a/force-app/main/default/classes/TriggerOrchestrator.cls +++ b/force-app/main/default/classes/TriggerOrchestrator.cls @@ -608,14 +608,15 @@ public with sharing class TriggerOrchestrator { Integer dmlStatementsBefore = Limits.getDmlStatements(); Integer immediateEventsBefore = Limits.getPublishImmediateDML(); - try { - super.execute(records); - } finally { - if (Limits.getDmlStatements() > dmlStatementsBefore || Limits.getPublishImmediateDML() > immediateEventsBefore) { - throw new TriggerOrchestratorException( - this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' - ); - } + super.execute(records); + + Integer dmlStatementsAfter = Limits.getDmlStatements(); + Integer immediateEventsAfter = Limits.getPublishImmediateDML(); + + if (dmlStatementsAfter > dmlStatementsBefore || immediateEventsAfter > immediateEventsBefore) { + throw new TriggerOrchestratorException( + this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' + ); } } @@ -663,14 +664,15 @@ public with sharing class TriggerOrchestrator { Integer dmlStatementsBefore = Limits.getDmlStatements(); Integer immediateEventsBefore = Limits.getPublishImmediateDML(); - try { - super.execute(records); - } finally { - if (Limits.getDmlStatements() > dmlStatementsBefore || Limits.getPublishImmediateDML() > immediateEventsBefore) { - throw new TriggerOrchestratorException( - this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' - ); - } + super.execute(records); + + Integer dmlStatementsAfter = Limits.getDmlStatements(); + Integer immediateEventsAfter = Limits.getPublishImmediateDML(); + + if (dmlStatementsAfter > dmlStatementsBefore || immediateEventsAfter > immediateEventsBefore) { + throw new TriggerOrchestratorException( + this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' + ); } } @@ -767,14 +769,15 @@ public with sharing class TriggerOrchestrator { Integer dmlStatementsBefore = Limits.getDmlStatements(); Integer immediateEventsBefore = Limits.getPublishImmediateDML(); - try { - super.execute(records); - } finally { - if (Limits.getDmlStatements() > dmlStatementsBefore || Limits.getPublishImmediateDML() > immediateEventsBefore) { - throw new TriggerOrchestratorException( - this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' - ); - } + super.execute(records); + + Integer dmlStatementsAfter = Limits.getDmlStatements(); + Integer immediateEventsAfter = Limits.getPublishImmediateDML(); + + if (dmlStatementsAfter > dmlStatementsBefore || immediateEventsAfter > immediateEventsBefore) { + throw new TriggerOrchestratorException( + this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' + ); } } @@ -868,14 +871,15 @@ public with sharing class TriggerOrchestrator { Integer dmlStatementsBefore = Limits.getDmlStatements(); Integer immediateEventsBefore = Limits.getPublishImmediateDML(); - try { - super.execute(records); - } finally { - if (Limits.getDmlStatements() > dmlStatementsBefore || Limits.getPublishImmediateDML() > immediateEventsBefore) { - throw new TriggerOrchestratorException( - this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' - ); - } + super.execute(records); + + Integer dmlStatementsAfter = Limits.getDmlStatements(); + Integer immediateEventsAfter = Limits.getPublishImmediateDML(); + + if (dmlStatementsAfter > dmlStatementsBefore || immediateEventsAfter > immediateEventsBefore) { + throw new TriggerOrchestratorException( + this.handlerName + ' performed DML in a before context. Populate the trigger record instead, or move the DML to an after context.' + ); } } From bc31f187f0ece20a891ac1716032876f14064af6 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 20 Sep 2026 21:03:48 +0200 Subject: [PATCH 4/7] Refactoring --- .../account/AccountTriggerOrchestrator.cls | 6 +- .../OpportunityTriggerOrchestrator.cls | 6 +- .../default/classes/TriggerOrchestrator.cls | 64 +------ .../classes/TriggerOrchestratorTest.cls | 164 ------------------ 4 files changed, 6 insertions(+), 234 deletions(-) diff --git a/examples/main/default/classes/account/AccountTriggerOrchestrator.cls b/examples/main/default/classes/account/AccountTriggerOrchestrator.cls index a3de9ce..7e48d39 100644 --- a/examples/main/default/classes/account/AccountTriggerOrchestrator.cls +++ b/examples/main/default/classes/account/AccountTriggerOrchestrator.cls @@ -1,8 +1,4 @@ -public with sharing class AccountTriggerOrchestrator implements TriggerOrchestrator.BeforeInsert, TriggerOrchestrator.AfterInsert, TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.AfterUpdate, TriggerOrchestrator.RecursionGuard { - public Integer maxRecursionDepth() { - return 2; - } - +public with sharing class AccountTriggerOrchestrator implements TriggerOrchestrator.BeforeInsert, TriggerOrchestrator.AfterInsert, TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.AfterUpdate { public List beforeInsertHandlers() { return new List{ new AccountParentDefaultsPopulator(), diff --git a/examples/main/default/classes/opportunity/OpportunityTriggerOrchestrator.cls b/examples/main/default/classes/opportunity/OpportunityTriggerOrchestrator.cls index fb354f1..a6b1738 100644 --- a/examples/main/default/classes/opportunity/OpportunityTriggerOrchestrator.cls +++ b/examples/main/default/classes/opportunity/OpportunityTriggerOrchestrator.cls @@ -1,8 +1,4 @@ -public with sharing class OpportunityTriggerOrchestrator implements TriggerOrchestrator.BeforeInsert, TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.AfterUpdate, TriggerOrchestrator.RecursionGuard { - public Integer maxRecursionDepth() { - return 2; - } - +public with sharing class OpportunityTriggerOrchestrator implements TriggerOrchestrator.BeforeInsert, TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.AfterUpdate { public List beforeInsertHandlers() { return new List{ new OpportunityCloseDatePopulator(), diff --git a/force-app/main/default/classes/TriggerOrchestrator.cls b/force-app/main/default/classes/TriggerOrchestrator.cls index c9d31a8..1f06250 100644 --- a/force-app/main/default/classes/TriggerOrchestrator.cls +++ b/force-app/main/default/classes/TriggerOrchestrator.cls @@ -45,10 +45,6 @@ public with sharing class TriggerOrchestrator { List afterUndeleteHandlers(); } - public interface RecursionGuard { - Integer maxRecursionDepth(); - } - public interface Logger { void log(TriggerOrchestrator.Error error); void finalize(); @@ -810,34 +806,8 @@ public with sharing class TriggerOrchestrator { } public override Boolean isRecursionDepthExceeded(TriggerHandler.TriggerRecord record) { - if (this.maxRecursionDepth == null) { - this.maxRecursionDepth = 3; - - if (this.orchestrator.orchestrator instanceof TriggerOrchestrator.RecursionGuard) { - this.maxRecursionDepth = ((TriggerOrchestrator.RecursionGuard) this.orchestrator.orchestrator).maxRecursionDepth(); - - if (this.maxRecursionDepth == null || this.maxRecursionDepth < 1) { - throw new TriggerOrchestratorException( - this.orchestrator.toString().substringBefore(':') + - ' returned a recursion depth of ' + - this.maxRecursionDepth + - ' from maxRecursionDepth(). The minimum is 1, meaning the handler runs once per record.' - ); - } - } - - if (this.handler instanceof BeforeUpdate.RecursionGuard) { - this.maxRecursionDepth = ((BeforeUpdate.RecursionGuard) this.handler).maxRecursionDepthOnBeforeUpdate(); - - if (this.maxRecursionDepth == null || this.maxRecursionDepth < 1) { - throw new TriggerOrchestratorException( - this.handlerName + - ' returned a recursion depth of ' + - this.maxRecursionDepth + - ' from maxRecursionDepthOnBeforeUpdate(). The minimum is 1, meaning the handler runs once per record.' - ); - } - } + if (this.maxRecursionDepth == null && this.handler instanceof BeforeUpdate.RecursionGuard) { + this.maxRecursionDepth = ((BeforeUpdate.RecursionGuard) this.handler).maxRecursionDepthOnBeforeUpdate(); } return (this.recursionDepthByRecord.get(record.getId()) ?? 0) >= this.maxRecursionDepth; @@ -964,34 +934,8 @@ public with sharing class TriggerOrchestrator { } public override Boolean isRecursionDepthExceeded(TriggerHandler.TriggerRecord record) { - if (this.maxRecursionDepth == null) { - this.maxRecursionDepth = 3; - - if (this.orchestrator.orchestrator instanceof TriggerOrchestrator.RecursionGuard) { - this.maxRecursionDepth = ((TriggerOrchestrator.RecursionGuard) this.orchestrator.orchestrator).maxRecursionDepth(); - - if (this.maxRecursionDepth == null || this.maxRecursionDepth < 1) { - throw new TriggerOrchestratorException( - this.orchestrator.toString().substringBefore(':') + - ' returned a recursion depth of ' + - this.maxRecursionDepth + - ' from maxRecursionDepth(). The minimum is 1, meaning the handler runs once per record.' - ); - } - } - - if (this.handler instanceof AfterUpdate.RecursionGuard) { - this.maxRecursionDepth = ((AfterUpdate.RecursionGuard) this.handler).maxRecursionDepthOnAfterUpdate(); - - if (this.maxRecursionDepth == null || this.maxRecursionDepth < 1) { - throw new TriggerOrchestratorException( - this.handlerName + - ' returned a recursion depth of ' + - this.maxRecursionDepth + - ' from maxRecursionDepthOnAfterUpdate(). The minimum is 1, meaning the handler runs once per record.' - ); - } - } + if (this.maxRecursionDepth == null && this.handler instanceof AfterUpdate.RecursionGuard) { + this.maxRecursionDepth = ((AfterUpdate.RecursionGuard) this.handler).maxRecursionDepthOnAfterUpdate(); } return (this.recursionDepthByRecord.get(record.getId()) ?? 0) >= this.maxRecursionDepth; diff --git a/force-app/main/default/classes/TriggerOrchestratorTest.cls b/force-app/main/default/classes/TriggerOrchestratorTest.cls index 9d5b422..996d8f7 100644 --- a/force-app/main/default/classes/TriggerOrchestratorTest.cls +++ b/force-app/main/default/classes/TriggerOrchestratorTest.cls @@ -3332,134 +3332,6 @@ private class TriggerOrchestratorTest { Assert.areEqual(2, handler.runCount, 'It should be 2.'); } - @IsTest - static void orchestratorRecursionGuardAppliesToEveryBeforeUpdateHandler() { - Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); - List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - - SOQL.mock('TriggerObject__mdt').thenReturn(new List()); - SOQL.mock('ApexTypeImplementor').thenReturn(new List()); - - RecursionBeforeUpdateHandler firstHandler = new RecursionBeforeUpdateHandler(); - RecursionSecondBeforeUpdateHandler secondHandler = new RecursionSecondBeforeUpdateHandler(); - - // Test - Test.startTest(); - for (Integer i = 0; i < 7; i++) { - TriggerOrchestrator orchestratorRunner = new TriggerOrchestrator( - new RecursionGuardedBeforeUpdateOrchestrator(new List{ firstHandler, secondHandler }, 5) - ); - orchestratorRunner.context.triggerOperation = System.TriggerOperation.BEFORE_UPDATE; - orchestratorRunner.context.newRecords = newRecords; - orchestratorRunner.context.oldRecords = oldRecords; - orchestratorRunner.run(); - } - Test.stopTest(); - - // Verify - Assert.areEqual(5, firstHandler.runCount, 'It should be 5.'); - Assert.areEqual(5, secondHandler.runCount, 'It should be 5.'); - } - - @IsTest - static void orchestratorRecursionGuardAppliesToEveryAfterUpdateHandler() { - Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); - List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - - SOQL.mock('TriggerObject__mdt').thenReturn(new List()); - SOQL.mock('ApexTypeImplementor').thenReturn(new List()); - - RecursionAfterUpdateHandler firstHandler = new RecursionAfterUpdateHandler(); - RecursionSecondAfterUpdateHandler secondHandler = new RecursionSecondAfterUpdateHandler(); - - // Test - Test.startTest(); - for (Integer i = 0; i < 7; i++) { - TriggerOrchestrator orchestratorRunner = new TriggerOrchestrator( - new RecursionGuardedAfterUpdateOrchestrator(new List{ firstHandler, secondHandler }, 5) - ); - orchestratorRunner.context.triggerOperation = System.TriggerOperation.AFTER_UPDATE; - orchestratorRunner.context.newRecords = newRecords; - orchestratorRunner.context.oldRecords = oldRecords; - orchestratorRunner.run(); - } - Test.stopTest(); - - // Verify - Assert.areEqual(5, firstHandler.runCount, 'It should be 5.'); - Assert.areEqual(5, secondHandler.runCount, 'It should be 5.'); - } - - @IsTest - static void handlerRecursionGuardBeatsOrchestratorRecursionGuardOnBeforeUpdate() { - Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); - List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - - SOQL.mock('TriggerObject__mdt').thenReturn(new List()); - SOQL.mock('ApexTypeImplementor').thenReturn(new List()); - - RecursionGuardedBeforeUpdateHandler guardedHandler = new RecursionGuardedBeforeUpdateHandler(2); - RecursionBeforeUpdateHandler unguardedHandler = new RecursionBeforeUpdateHandler(); - - // Test - Test.startTest(); - for (Integer i = 0; i < 7; i++) { - TriggerOrchestrator orchestratorRunner = new TriggerOrchestrator( - new RecursionGuardedBeforeUpdateOrchestrator(new List{ guardedHandler, unguardedHandler }, 5) - ); - orchestratorRunner.context.triggerOperation = System.TriggerOperation.BEFORE_UPDATE; - orchestratorRunner.context.newRecords = newRecords; - orchestratorRunner.context.oldRecords = oldRecords; - orchestratorRunner.run(); - } - Test.stopTest(); - - // Verify - Assert.areEqual( - 2, - guardedHandler.runCount, - 'It should be 2, because BeforeUpdate.RecursionGuard on the handler is resolved last and always wins over TriggerOrchestrator.RecursionGuard.' - ); - Assert.areEqual(5, unguardedHandler.runCount, 'It should be 5.'); - } - - @IsTest - static void handlerRecursionGuardBeatsOrchestratorRecursionGuardOnAfterUpdate() { - Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); - List newRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - List oldRecords = new List{ new Contact(Id = contactId, LastName = 'Ada') }; - - SOQL.mock('TriggerObject__mdt').thenReturn(new List()); - SOQL.mock('ApexTypeImplementor').thenReturn(new List()); - - RecursionGuardedAfterUpdateHandler guardedHandler = new RecursionGuardedAfterUpdateHandler(2); - RecursionAfterUpdateHandler unguardedHandler = new RecursionAfterUpdateHandler(); - - // Test - Test.startTest(); - for (Integer i = 0; i < 7; i++) { - TriggerOrchestrator orchestratorRunner = new TriggerOrchestrator( - new RecursionGuardedAfterUpdateOrchestrator(new List{ guardedHandler, unguardedHandler }, 5) - ); - orchestratorRunner.context.triggerOperation = System.TriggerOperation.AFTER_UPDATE; - orchestratorRunner.context.newRecords = newRecords; - orchestratorRunner.context.oldRecords = oldRecords; - orchestratorRunner.run(); - } - Test.stopTest(); - - // Verify - Assert.areEqual( - 2, - guardedHandler.runCount, - 'It should be 2, because AfterUpdate.RecursionGuard on the handler is resolved last and always wins over TriggerOrchestrator.RecursionGuard.' - ); - Assert.areEqual(5, unguardedHandler.runCount, 'It should be 5.'); - } - @IsTest static void noRecursionGuardAnywhereFallsBackToThreePassesOnBeforeUpdate() { Id contactId = TriggerHandler.IdGenerator.get(Contact.SObjectType); @@ -9094,24 +8966,6 @@ private class TriggerOrchestratorTest { } } - private class RecursionGuardedBeforeUpdateOrchestrator implements TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.RecursionGuard { - private List handlers; - private Integer maxRecursionDepth; - - public RecursionGuardedBeforeUpdateOrchestrator(List handlers, Integer maxRecursionDepth) { - this.handlers = handlers; - this.maxRecursionDepth = maxRecursionDepth; - } - - public Integer maxRecursionDepth() { - return this.maxRecursionDepth; - } - - public List beforeUpdateHandlers() { - return this.handlers; - } - } - private class RecursionAfterUpdateOrchestrator implements TriggerOrchestrator.AfterUpdate { private List handlers; @@ -9124,24 +8978,6 @@ private class TriggerOrchestratorTest { } } - private class RecursionGuardedAfterUpdateOrchestrator implements TriggerOrchestrator.AfterUpdate, TriggerOrchestrator.RecursionGuard { - private List handlers; - private Integer maxRecursionDepth; - - public RecursionGuardedAfterUpdateOrchestrator(List handlers, Integer maxRecursionDepth) { - this.handlers = handlers; - this.maxRecursionDepth = maxRecursionDepth; - } - - public Integer maxRecursionDepth() { - return this.maxRecursionDepth; - } - - public List afterUpdateHandlers() { - return this.handlers; - } - } - private class RecursionBothUpdatesOrchestrator implements TriggerOrchestrator.BeforeUpdate, TriggerOrchestrator.AfterUpdate { private RecursionBothUpdatesHandler handler; From 90c6aca705ffb36b019910dab4955c5c5325071d Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Sun, 20 Sep 2026 22:04:12 +0200 Subject: [PATCH 5/7] Refactoring --- .../default/classes/TriggerOrchestrator.cls | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/force-app/main/default/classes/TriggerOrchestrator.cls b/force-app/main/default/classes/TriggerOrchestrator.cls index 1f06250..362c6c1 100644 --- a/force-app/main/default/classes/TriggerOrchestrator.cls +++ b/force-app/main/default/classes/TriggerOrchestrator.cls @@ -343,11 +343,7 @@ public with sharing class TriggerOrchestrator { orchestrator.lookupEnrichment.queryParentRelationships(activeHandlers); for (TriggerHandlerAdapter adapter : activeHandlers) { - try { - adapter.execute(orchestrator.context.triggerRecords); - } catch (Exception e) { - adapter.handleException(e); - } + adapter.execute(orchestrator.context.triggerRecords); orchestrator.lookupEnrichment.requeryWhenParentLookupChanged(adapter.getProcessedRecords()); } @@ -535,20 +531,24 @@ public with sharing class TriggerOrchestrator { } public virtual void execute(List records) { - for (TriggerHandler.TriggerRecord record : records) { - if (this.isRecursionDepthExceeded(record)) { - continue; - } + try { + for (TriggerHandler.TriggerRecord record : records) { + if (this.isRecursionDepthExceeded(record)) { + continue; + } - if (!this.isQualified(record)) { - continue; - } + if (!this.isQualified(record)) { + continue; + } - this.registerRecord(record); + this.registerRecord(record); - this.processedRecords.add(record); + this.processedRecords.add(record); - this.executeOn(record); + this.executeOn(record); + } + } catch (Exception e) { + this.handleException(e); } if (!this.processedRecords.isEmpty()) { @@ -561,17 +561,13 @@ public with sharing class TriggerOrchestrator { } public void handleException(Exception e) { - this.logError(e); + TriggerOrchestrator.triggerLogger.log(new TriggerError().withException(e).withHandlerName(this.handlerName).withContext(this.orchestrator.context)); if (e instanceof TriggerOrchestratorException || e instanceof TriggerHandler.TriggerHandlerException || !this.continuesOnError()) { throw e; } } - private void logError(Exception e) { - TriggerOrchestrator.triggerLogger.log(new TriggerError().withException(e).withHandlerName(this.handlerName).withContext(this.orchestrator.context)); - } - public Boolean isBypassed() { return this.isBypassedBySettings() || this.isBypassedByHandler(); } From f1b0bf687f59997b53a1a92a5e4d6dcdbc2cc7a8 Mon Sep 17 00:00:00 2001 From: Maciej Ptak <0ptaq0@gmail.com> Date: Sun, 20 Sep 2026 22:35:00 +0200 Subject: [PATCH 6/7] ci: test deploy error report from template branch --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72436d7..97a6758 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: jobs: salesforce-ci: - uses: beyond-the-cloud-dev/cicd-template/.github/workflows/salesforce-ci.yml@main + uses: beyond-the-cloud-dev/cicd-template/.github/workflows/salesforce-ci.yml@feat/deploy-error-report with: node-version: "22" sf-cli-version: "latest" From b34babb67126b9abd484a73f5993a7d364f6d201 Mon Sep 17 00:00:00 2001 From: Maciej Ptak <0ptaq0@gmail.com> Date: Sun, 20 Sep 2026 22:37:31 +0200 Subject: [PATCH 7/7] ci: pass template-ref for test --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97a6758..57097d2 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ jobs: sf-cli-version: "latest" scratch-org-duration: 1 test-level: "RunLocalTests" + template-ref: feat/deploy-error-report upload-to-codecov: true codecov-slug: ${{ github.repository }} # Automatically uses current repository secrets: