From fe39523b4e4c7a580fe2ad8dd5783902492e5df9 Mon Sep 17 00:00:00 2001 From: Jonathan Gillespie Date: Wed, 16 Mar 2022 08:57:06 -0400 Subject: [PATCH] Added tests for execute methods in LoggerSObjectHandler --- .../classes/LoggerSObjectHandler.cls | 50 ++-- .../classes/LoggerSObjectHandler_Tests.cls | 266 +++++++++++++++--- 2 files changed, 268 insertions(+), 48 deletions(-) diff --git a/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls b/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls index f88c26134..7471958f9 100644 --- a/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls +++ b/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls @@ -12,15 +12,27 @@ public without sharing abstract class LoggerSObjectHandler { private static final Map> SOBJECT_TYPE_TO_EXECUTED_HANDLERS = new Map>(); private static final Map> SOBJECT_TYPE_TO_MOCK_PLUGIN_CONFIGURATIONS = new Map>(); + @TestVisible + private TriggerOperation triggerOperationType; + @TestVisible + private List triggerNew; + @TestVisible + private Map triggerNewMap; + @TestVisible + private Map triggerOldMap; private SObjectHandlerInput input; - private List pluginConfigurations; + private List pluginConfigurations = new List(); private List executedApexPlugins = new List(); /** * @description Default constructor */ public LoggerSObjectHandler() { - this.createSObjectHandlerInput(); + this.triggerOperationType = Trigger.operationType; + this.triggerNew = Trigger.new; + this.triggerNewMap = Trigger.newMap; + this.triggerOldMap = Trigger.oldMap; + this.queryPluginConfigurations(); } @@ -61,6 +73,8 @@ public without sharing abstract class LoggerSObjectHandler { return; } + this.createSObjectHandlerInput(); + switch on this.input.triggerOperationType { when BEFORE_INSERT { this.executeBeforeInsert(this.input.triggerNew); @@ -129,11 +143,10 @@ public without sharing abstract class LoggerSObjectHandler { // Trigger variables for Apex Developers input.sobjectType = this.getSObjectType(); - input.triggerOperationType = Trigger.operationType; - input.triggerNew = Trigger.new; - input.triggerNewMap = Trigger.newMap; - input.triggerOld = Trigger.old; - input.triggerOldMap = Trigger.oldMap; + input.triggerOperationType = triggerOperationType; + input.triggerNew = triggerNew; + input.triggerNewMap = triggerNewMap; + input.triggerOldMap = triggerOldMap; // Additional invocable variables for Flow Builders (and Apex Developers too, if they want to use them) input.sobjectTypeName = this.getSObjectType().getDescribe().getName(); @@ -149,8 +162,8 @@ public without sharing abstract class LoggerSObjectHandler { input.triggerRecords.add(recordInput); } - } else if (input.triggerOld != null) { - for (SObject record : input.triggerOld) { + } else if (input.triggerOldMap != null) { + for (SObject record : input.triggerOldMap.values()) { SObjectHandlerRecordInput recordInput = new SObjectHandlerRecordInput(); recordInput.triggerRecordOld = record; @@ -221,7 +234,13 @@ public without sharing abstract class LoggerSObjectHandler { apexPlugin.execute(configuration, this.input); // TODO Legacy approach, remove in a future release - apexPlugin.execute(this.input.triggerOperationType, this.input.triggerNew, this.input.triggerNewMap, this.input.triggerOld, this.input.triggerOldMap); + apexPlugin.execute( + this.input.triggerOperationType, + this.input.triggerNew, + this.input.triggerNewMap, + this.input.triggerOldMap?.values(), + this.input.triggerOldMap + ); if (Test.isRunningTest() == true) { this.executedApexPlugins.add(apexPlugin); @@ -236,7 +255,7 @@ public without sharing abstract class LoggerSObjectHandler { // TODO Legacy approach, remove in a future release flowInputs.put('triggerOperationType', this.input.triggerOperationType?.name()); flowInputs.put('triggerNew', this.input.triggerNew); - flowInputs.put('triggerOld', this.input.triggerOld); + flowInputs.put('triggerOld', this.input.triggerOldMap?.values()); try { Flow.Interview flowPlugin = Flow.Interview.createInterview(configuration.PluginApiName__c, flowInputs); @@ -254,10 +273,10 @@ public without sharing abstract class LoggerSObjectHandler { } } - // Instance test helper methods + // Instance test helper methods, used for unit tests @TestVisible - private void setMockInput(SObjectHandlerInput input) { - this.input = input; + private List getPluginConfigurations() { + return this.pluginConfigurations; } @TestVisible @@ -270,7 +289,7 @@ public without sharing abstract class LoggerSObjectHandler { return this.executedApexPlugins; } - // Static test helper methods + // Static test helper methods, used for integration tests @TestVisible private static Map> getExecutedHandlers() { return SOBJECT_TYPE_TO_EXECUTED_HANDLERS; @@ -292,7 +311,6 @@ public without sharing abstract class LoggerSObjectHandler { public TriggerOperation triggerOperationType; public List triggerNew; public Map triggerNewMap; - public List triggerOld; public Map triggerOldMap; @InvocableVariable(label='SObject Type Name') diff --git a/nebula-logger/core/tests/log-management/classes/LoggerSObjectHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerSObjectHandler_Tests.cls index aed7f7898..99fd73f52 100644 --- a/nebula-logger/core/tests/log-management/classes/LoggerSObjectHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LoggerSObjectHandler_Tests.cls @@ -5,63 +5,265 @@ @IsTest private class LoggerSObjectHandler_Tests { - private class MockLogHandler extends LoggerSObjectHandler { - public override SObjectType getSObjectType() { - return Schema.Log__c.SObjectType; - } + private static final String HANDLER_CONTROL_PARAMETER_NAME = 'IsMockLogHandlerEnabled'; - public override String getHandlerControlParameterName() { - return 'IsLogHandlerEnabled'; - } + @TestSetup + static void setupData() { + insert new Log__c(TransactionId__c = '1234'); + } - public override Schema.SObjectField getHandlerPluginControlField() { - return Schema.LoggerPlugin__mdt.IsLogEnabled__c; - } + @IsTest + static void it_should_not_run_when_disabled_via_logger_parameter() { + LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = HANDLER_CONTROL_PARAMETER_NAME, Value__c = 'false')); + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + handler.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + handler.triggerNewMap = null; + handler.triggerOldMap = null; - public override Schema.SObjectField getHandlerPluginSortField() { - return Schema.LoggerPlugin__mdt.LogExecutionOrder__c; - } + handler.execute(); + + System.assertEquals(0, handler.executionCount); } @IsTest - static void it_should_gracefully_skip_non_existent_apex_plugin() { - LoggerSObjectHandler.SObjectHandlerInput input = new LoggerSObjectHandler.SObjectHandlerInput(); - input.sobjectType = Schema.Log__c.SObjectType; - input.triggerOperationType = TriggerOperation.BEFORE_INSERT; - input.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + static void it_should_run_before_insert_method() { + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + handler.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + handler.triggerNewMap = null; + handler.triggerOldMap = null; + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_INSERT, handler.executedTriggerOperationType); + System.assertEquals(handler.triggerNew, handler.executedTriggerNew); + System.assertEquals(null, handler.executedTriggerNewMap); + System.assertEquals(null, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_before_update_method() { + List records = [SELECT Id, TransactionId__c FROM Log__c]; + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_UPDATE; + handler.triggerNew = null; + handler.triggerNewMap = new Map(records); + handler.triggerOldMap = new Map(records); + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_UPDATE, handler.executedTriggerOperationType); + System.assertEquals(null, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(handler.triggerOldMap, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_before_delete_method() { + List records = [SELECT Id, TransactionId__c FROM Log__c]; + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_DELETE; + handler.triggerNew = null; + handler.triggerNewMap = new Map(records); + handler.triggerOldMap = null; + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_DELETE, handler.executedTriggerOperationType); + System.assertEquals(null, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(null, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_insert_methods() { + // To handle AFTER_INSERT on LogEntryEvent__e, LoggerSObjectHandler has 2 methods - one with + // a list of SObject records (triggerNew), and another with a map of SObject records (triggerNewMap) + List records = [SELECT Id, TransactionId__c FROM Log__c]; + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.AFTER_INSERT; + handler.triggerNew = records; + handler.triggerNewMap = new Map(records); + handler.triggerOldMap = null; + + handler.execute(); + + System.assertEquals(2, handler.executionCount); + System.assertEquals(TriggerOperation.AFTER_INSERT, handler.executedTriggerOperationType); + System.assertEquals(handler.triggerNew, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(null, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_update_method() { + List records = [SELECT Id, TransactionId__c FROM Log__c]; + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.AFTER_UPDATE; + handler.triggerNew = null; + handler.triggerNewMap = new Map(records); + handler.triggerOldMap = new Map(records); + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.AFTER_UPDATE, handler.executedTriggerOperationType); + System.assertEquals(null, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(handler.triggerOldMap, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_delete_method() { + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.AFTER_DELETE; + handler.triggerNew = null; + handler.triggerNewMap = new Map([SELECT Id, TransactionId__c FROM Log__c]); + handler.triggerOldMap = null; + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.AFTER_DELETE, handler.executedTriggerOperationType); + System.assertEquals(null, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(null, handler.executedTriggerOldMap); + } + @IsTest + static void it_should_run_after_undelete_method() { + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.AFTER_UNDELETE; + handler.triggerNew = null; + handler.triggerNewMap = new Map([SELECT Id, TransactionId__c FROM Log__c]); + handler.triggerOldMap = null; + + handler.execute(); + + System.assertEquals(1, handler.executionCount); + System.assertEquals(TriggerOperation.AFTER_UNDELETE, handler.executedTriggerOperationType); + System.assertEquals(null, handler.executedTriggerNew); + System.assertEquals(handler.triggerNewMap, handler.executedTriggerNewMap); + System.assertEquals(null, handler.executedTriggerOldMap); + } + + @IsTest + static void it_should_gracefully_skip_non_existent_apex_plugin() { + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + handler.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + handler.triggerNewMap = null; + handler.triggerOldMap = null; LoggerPlugin__mdt plugin = new LoggerPlugin__mdt( IsEnabled__c = true, IsLogEnabled__c = true, PluginApiName__c = 'Some_Fake_Apex_Class', PluginType__c = 'Apex' ); + handler.addMockPlugin(plugin); - LoggerSObjectHandler mockLogHandler = new MockLogHandler(); - mockLogHandler.setMockInput(input); - mockLogHandler.addMockPlugin(plugin); - mockLogHandler.execute(); + handler.execute(); - System.assertEquals(0, mockLogHandler.getExecutedApexPlugins().size()); + System.assertEquals(1, handler.getPluginConfigurations().size()); + System.assertEquals(0, handler.getExecutedApexPlugins().size()); } @IsTest static void it_should_gracefully_skip_non_existent_flow_plugin() { - LoggerSObjectHandler.SObjectHandlerInput input = new LoggerSObjectHandler.SObjectHandlerInput(); - input.sobjectType = Schema.Log__c.SObjectType; - input.triggerOperationType = TriggerOperation.BEFORE_INSERT; - input.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; - + MockLogHandler handler = new MockLogHandler(); + handler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + handler.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + handler.triggerNewMap = null; + handler.triggerOldMap = null; LoggerPlugin__mdt plugin = new LoggerPlugin__mdt( IsEnabled__c = true, IsLogEnabled__c = true, PluginApiName__c = 'Some_Fake_Flow', PluginType__c = 'Flow' ); + handler.addMockPlugin(plugin); + + handler.execute(); + + System.assertEquals(1, handler.getPluginConfigurations().size()); + System.assertEquals(0, handler.getExecutedApexPlugins().size()); + } + + public class MockLogHandler extends LoggerSObjectHandler { + public Integer executionCount = 0; + public TriggerOperation executedTriggerOperationType; + public List executedTriggerNew; + public Map executedTriggerNewMap; + public Map executedTriggerOldMap; + + public override SObjectType getSObjectType() { + return Schema.Log__c.SObjectType; + } + + public override String getHandlerControlParameterName() { + return HANDLER_CONTROL_PARAMETER_NAME; + } + + public override Schema.SObjectField getHandlerPluginControlField() { + return Schema.LoggerPlugin__mdt.IsLogEnabled__c; + } + + public override Schema.SObjectField getHandlerPluginSortField() { + return Schema.LoggerPlugin__mdt.LogExecutionOrder__c; + } - LoggerSObjectHandler mockLogHandler = new MockLogHandler(); - mockLogHandler.setMockInput(input); - mockLogHandler.addMockPlugin(plugin); - mockLogHandler.execute(); + protected override void executeBeforeInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_INSERT; + this.executedTriggerNew = triggerNew; + } + + protected override void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + } + + protected override void executeBeforeDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_DELETE; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNew = triggerNew; + } + + protected override void executeAfterInsert(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + } + + protected override void executeAfterDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_DELETE; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterUndelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UNDELETE; + this.executedTriggerNewMap = triggerNewMap; + } } }