Skip to content

Commit

Permalink
Made additional improvements to the tests for LoggerEngineDataSelecto…
Browse files Browse the repository at this point in the history
…r and LogManagementDataSelector to improve testing + test coverage
  • Loading branch information
jongpie committed Dec 10, 2024
1 parent 5f3c4e7 commit 5520135
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
@SuppressWarnings('PMD.ApexCRUDViolation, PMD.CyclomaticComplexity, PMD.ExcessivePublicCount')
public without sharing virtual class LogManagementDataSelector {
private static final Boolean IS_OMNISTUDIO_ENABLED = System.Type.forName('Schema.OmniProcess') != null;

private static LogManagementDataSelector instance = new LogManagementDataSelector();

@SuppressWarnings('PMD.EmptyStatementBlock')
Expand Down Expand Up @@ -311,11 +313,14 @@ public without sharing virtual class LogManagementDataSelector {
String query =
'SELECT CreatedBy.Username, CreatedById, CreatedDate, Id, IsIntegrationProcedure, LastModifiedBy.Username, LastModifiedById, LastModifiedDate, OmniProcessType, UniqueName' +
' FROM OmniProcess WHERE Id IN :omniProcessIds';
for (SObject omniProcessRecord : System.Database.query(String.escapeSingleQuotes(query))) {
LoggerSObjectProxy.OmniProcess omniProcessProxy = (LoggerSObjectProxy.OmniProcess) System.JSON.deserialize(
System.JSON.serialize(omniProcessRecord),
LoggerSObjectProxy.OmniProcess.class
);
List<SObject> omniProcessRecords = IS_OMNISTUDIO_ENABLED ? System.Database.query(String.escapeSingleQuotes(query)) : new List<SObject>();

List<LoggerSObjectProxy.OmniProcess> omniProcessProxies = (List<LoggerSObjectProxy.OmniProcess>) System.JSON.deserialize(
System.JSON.serialize(omniProcessRecords),
List<LoggerSObjectProxy.OmniProcess>.class
);

for (LoggerSObjectProxy.OmniProcess omniProcessProxy : omniProcessProxies) {
omniProcessIdToOmniProcessProxy.put(omniProcessProxy.Id, omniProcessProxy);
}
return omniProcessIdToOmniProcessProxy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,8 @@ public without sharing virtual class LoggerEngineDataSelector {
return (LoggerSObjectProxy.AuthSession) LoggerCache.getSessionCache().get(cacheKey);
}

LoggerSObjectProxy.AuthSession authSessionProxy;
if (LoggerParameter.QUERY_AUTH_SESSION_DATA) {
authSessionProxy = getAuthSessionProxies(new List<Id>{ userId }).get(userId);
LoggerCache.getSessionCache().put(cacheKey, authSessionProxy);
}
LoggerSObjectProxy.AuthSession authSessionProxy = getAuthSessionProxies(new List<Id>{ userId }).get(userId);
LoggerCache.getSessionCache().put(cacheKey, authSessionProxy);
return authSessionProxy;
}

Expand All @@ -107,7 +104,7 @@ public without sharing virtual class LoggerEngineDataSelector {
* @return The cached `Schema.Network` record
*/
public virtual LoggerSObjectProxy.Network getCachedNetworkProxy(Id networkId) {
if (networkId == null || (IS_EXPERIENCE_CLOUD_ENABLED == false && mockNetworkProxies == null)) {
if (networkId == null) {
return null;
}

Expand All @@ -116,11 +113,8 @@ public without sharing virtual class LoggerEngineDataSelector {
return (LoggerSObjectProxy.Network) LoggerCache.getOrganizationCache().get(cacheKey);
}

LoggerSObjectProxy.Network networkProxy;
if (LoggerParameter.QUERY_NETWORK_DATA) {
networkProxy = getNetworkProxies(new List<Id>{ networkId }).get(networkId);
LoggerCache.getOrganizationCache().put(cacheKey, networkProxy);
}
LoggerSObjectProxy.Network networkProxy = getNetworkProxies(new List<Id>{ networkId }).get(networkId);
LoggerCache.getOrganizationCache().put(cacheKey, networkProxy);
return networkProxy;
}

Expand Down Expand Up @@ -181,14 +175,14 @@ public without sharing virtual class LoggerEngineDataSelector {
* @return The instance of `Map<Id, SObject>` containing any matching `Schema.Network` records
*/
public Map<Id, LoggerSObjectProxy.Network> getNetworkProxies(List<Id> networkIds) {
// TODO add caching in a future release
Map<Id, LoggerSObjectProxy.Network> networkIdToNetworkProxy = new Map<Id, LoggerSObjectProxy.Network>();
if (LoggerParameter.QUERY_NETWORK_DATA == false) {
return null;
return networkIdToNetworkProxy;
}

// Networks (aka experience sites aka community sites aka portal sites ò_ô)
// may not be enabled in the org (no Schema.Network object), so run everything dynamically
Map<Id, LoggerSObjectProxy.Network> networkIdToNetworkProxy = new Map<Id, LoggerSObjectProxy.Network>();

String query = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id IN :networkIds';
List<SObject> networkRecords = IS_EXPERIENCE_CLOUD_ENABLED ? System.Database.query(String.escapeSingleQuotes(query)) : new List<SObject>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.MethodNamingConventions')
@IsTest(IsParallel=false)
private class LogManagementDataSelector_Tests {
private static final Boolean IS_OMNISTUDIO_ENABLED = System.Type.forName('Schema.OmniProcess') != null;

static {
// Don't use the org's actual custom metadata records when running tests
LoggerConfigurationSelector.useMocks();
Expand Down Expand Up @@ -60,6 +58,7 @@ private class LogManagementDataSelector_Tests {
Set<String> targetApexClassNames = new Set<String>{ 'SomeClass', 'AnotherClass' };
Integer originalQueryCount = System.Limits.getQueries();
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryApexClassData', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_APEX_CLASS_DATA);

List<Schema.ApexClass> returnedResults = LogManagementDataSelector.getInstance().getApexClasses(targetApexClassNames);

Expand Down Expand Up @@ -88,6 +87,7 @@ private class LogManagementDataSelector_Tests {
Set<String> targetApexTriggerNames = new Set<String>{ 'SomeTrigger', 'AnotherTrigger' };
Integer originalQueryCount = System.Limits.getQueries();
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryApexTriggerData', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_APEX_TRIGGER_DATA);

List<Schema.ApexTrigger> returnedResults = LogManagementDataSelector.getInstance().getApexTriggers(targetApexTriggerNames);

Expand All @@ -108,26 +108,6 @@ private class LogManagementDataSelector_Tests {
System.Assert.areEqual(expectedResults, returnedResults);
}

// FIXME Querying AsyncApexJob in a test context doesn't seem to return results for @future methods,
// and the @future method should be replaced with a queueable class anyway, so fix this test
// when converting the @future method to a private queueable class
// @IsTest
// static void it_returns_count_of_async_apex_jobs_for_specified_class_method_and_statuses() {
// String apexClassName = LogManagementDataSelector_Tests.class.getName();
// String apexMethodName = 'executeSomeFutureMethod';
// List<String> jobStatuses = new List<String>{ 'Holding', 'Queued', 'Preparing', 'Processing' };
// System.Assert.areEqual(0, LogManagementDataSelector.getInstance().getCountOfAsyncApexJobs(apexClassName, apexMethodName, jobStatuses));

// System.Test.startTest();
// executeSomeFutureMethod();
// System.Test.stopTest();

// System.Assert.fail([SELECT status FROM AsyncApexJob]);
// Integer returnedCount = LogManagementDataSelector.getInstance().getCountOfAsyncApexJobs(apexClassName, apexMethodName, jobStatuses);

// System.Assert.areEqual(1, returnedCount);
// }

@IsTest
static void it_returns_cached_recent_log_with_api_release_details_when_call_status_api_callout_is_enabled() {
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = System.JSON.serialize(true)));
Expand Down Expand Up @@ -162,6 +142,22 @@ private class LogManagementDataSelector_Tests {
System.Assert.areEqual(2, System.Limits.getQueries());
}

@IsTest
static void it_returns_count_of_async_apex_jobs_for_specified_apex_class_and_method_name() {
// Even though an inner class is used, the AsyncApexJob
String apexClassName = LogManagementDataSelector_Tests.class.getName();
String apexMethodName = null;
List<String> jobStatuses = new List<String>{ 'Completed' };
System.Assert.areEqual(0, LogManagementDataSelector.getInstance().getCountOfAsyncApexJobs(apexClassName, apexMethodName, jobStatuses));

System.Test.startTest();
System.enqueueJob(new ExampleQueuable());
System.Test.stopTest();

Integer returnedCount = LogManagementDataSelector.getInstance().getCountOfAsyncApexJobs(apexClassName, apexMethodName, jobStatuses);
System.Assert.areEqual(1, returnedCount);
}

@IsTest
static void it_returns_null_when_no_recent_log_with_api_release_details_is_found() {
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = System.JSON.serialize(true)));
Expand Down Expand Up @@ -238,6 +234,44 @@ private class LogManagementDataSelector_Tests {
System.Assert.areEqual(deleteableRecord.Id, returnedResults.get(0).RecordId);
}

@IsTest
static void it_does_not_query_flow_definition_view_when_disabled_via_logger_parameter() {
// The IDs used in the query don't particularly matter here - the main concern is checking that the query does not execute at all
List<Id> targetFlowDefinitionViewIds = new List<Id>{ System.UserInfo.getUserId() };
Integer originalQueryCount = System.Limits.getQueries();
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryFlowDefinitionViewData', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_FLOW_DEFINITION_VIEW_DATA);

List<Schema.FlowDefinitionView> returnedResults = LogManagementDataSelector.getInstance().getFlowDefinitionViewsByFlowApiName(targetFlowDefinitionViewIds);

System.Assert.areEqual(originalQueryCount, System.Limits.getQueries());
System.Assert.areEqual(0, returnedResults.size());
}

@IsTest
static void it_returns_flow_definition_view_for_nonexistent_api_name() {
LoggerSObjectHandler.shouldExecute(false);
String fakeFlowApiName = 'Some Flow API Name That Cannot Exist Because It Has Spaces and Emojis 👈👈😎, THUS, We CAN Safely Call This A Fake API Name';

List<Schema.FlowDefinitionView> returnedResults = LogManagementDataSelector.getInstance()
.getFlowDefinitionViewsByFlowApiName(new List<String>{ fakeFlowApiName });

System.Assert.isNotNull(returnedResults);
System.Assert.isTrue(returnedResults.isEmpty());
}

@IsTest
static void it_returns_flow_version_view_for_nonexistent_durable_ids() {
LoggerSObjectHandler.shouldExecute(false);
String fakeFlowDurableId = 'Some Flow API Name That Cannot Exist Because It Has Spaces and Emojis 👈👈😎, THUS, We CAN Safely Call This A Fake API Name';

List<Schema.FlowVersionView> returnedResults = LogManagementDataSelector.getInstance()
.getFlowVersionViewsByDurableId(new List<String>{ fakeFlowDurableId });

System.Assert.isNotNull(returnedResults);
System.Assert.isTrue(returnedResults.isEmpty());
}

@IsTest
static void it_returns_log_for_specified_log_id() {
LoggerSObjectHandler.shouldExecute(false);
Expand Down Expand Up @@ -385,11 +419,7 @@ private class LogManagementDataSelector_Tests {
}

@IsTest
static void it_returns_omni_processes_for_specified_ids() {
// No need to fail the test if it's running in an org that does not have OmniStudio enabled
if (IS_OMNISTUDIO_ENABLED == false) {
return;
}
static void it_returns_omni_processes_for_empty_list_of_ids() {
// Fun fact: in an anonymous Apex script, you can easily create an OmniProcess record...
// ...but when you create one in a test class, you get a gack error 🥲
// Because of this platform limitation, this test is not great - it doesn't create records (because it can't),
Expand All @@ -398,9 +428,10 @@ private class LogManagementDataSelector_Tests {
// TODO revisit to see if there is any other way to create OmniProcess records to improve this test.
List<String> omniProcessIds = new List<Id>();

List<SObject> returnedResults = LogManagementDataSelector.getInstance().getLoggerScenariosById(omniProcessIds);
Map<Id, LoggerSObjectProxy.OmniProcess> returnedResults = LogManagementDataSelector.getInstance().getOmniProcessProxies(omniProcessIds);

System.Assert.isNotNull(returnedResults);
System.Assert.isTrue(returnedResults.isEmpty());
}

@IsTest
Expand All @@ -409,6 +440,7 @@ private class LogManagementDataSelector_Tests {
List<Id> targetOmniProcessIds = new List<Id>{ System.UserInfo.getUserId() };
Integer originalQueryCount = System.Limits.getQueries();
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryOmniProcessData', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_OMNI_PROCESS_DATA);

Map<Id, LoggerSObjectProxy.OmniProcess> returnedResults = LogManagementDataSelector.getInstance().getOmniProcessProxies(targetOmniProcessIds);

Expand Down Expand Up @@ -585,12 +617,13 @@ private class LogManagementDataSelector_Tests {
System.Assert.areEqual(mockSelector, LogManagementDataSelector.getInstance());
}

@SuppressWarnings('PMD.EmptyStatementBlock')
@future
private static void executeSomeFutureMethod() {
// This method intentionally does nothing - it\'s only used to help test queries on AsynxApexJob
private class MockLogManagementDataSelector extends LogManagementDataSelector {
}

private class MockLogManagementDataSelector extends LogManagementDataSelector {
private class ExampleQueuable implements System.Queueable {
@SuppressWarnings('PMD.EmptyStatementBlock')
public void execute(System.QueueableContext queueableContext) {
// No-op, just for testing purposes
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,21 @@ private class LoggerEngineDataSelector_Tests {
}

@IsTest
static void it_returns_cached_auth_session_proxy() {
static void it_returns_cached_auth_session_proxy_when_populated_in_cache() {
System.Assert.isTrue(LoggerParameter.QUERY_AUTH_SESSION_DATA);
System.Assert.areEqual(0, System.Limits.getQueries());
LoggerEngineDataSelector.useMocks();
LoggerSObjectProxy.AuthSession mockAuthSessionProxy = new LoggerSObjectProxy.AuthSession();
LoggerCache.getOrganizationCache().put('AuthSession' + System.UserInfo.getUserId(), mockAuthSessionProxy);

LoggerSObjectProxy.AuthSession returnedAuthSessionProxy = LoggerEngineDataSelector.getInstance().getCachedAuthSessionProxy();

System.Assert.areEqual(0, System.Limits.getQueries());
System.Assert.areEqual(mockAuthSessionProxy, returnedAuthSessionProxy);
}

@IsTest
static void it_returns_queried_auth_session_proxy_when_cache_is_not_populated() {
List<Schema.AuthSession> sessions = [
SELECT
Id,
Expand Down Expand Up @@ -52,6 +66,21 @@ private class LoggerEngineDataSelector_Tests {
System.Assert.areEqual(expectedAuthSessionProxy, returnedAuthSessionProxy);
}

@IsTest
static void it_returns_mock_auth_session_proxy_when_mock_is_provided() {
System.Assert.isTrue(LoggerParameter.QUERY_AUTH_SESSION_DATA);
System.Assert.areEqual(0, System.Limits.getQueries());
LoggerEngineDataSelector.useMocks();
LoggerSObjectProxy.AuthSession mockAuthSessionProxy = new LoggerSObjectProxy.AuthSession();
mockAuthSessionProxy.UsersId = System.UserInfo.getUserId();
LoggerEngineDataSelector.mockAuthSessionProxies.add(mockAuthSessionProxy);

LoggerSObjectProxy.AuthSession returnedAuthSessionProxy = LoggerEngineDataSelector.getInstance().getCachedAuthSessionProxy();

System.Assert.areEqual(1, System.Limits.getQueries());
System.Assert.areEqual(mockAuthSessionProxy, returnedAuthSessionProxy);
}

@IsTest
static void it_returns_null_when_querying_auth_session_is_disabled() {
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryAuthSessionData', Value__c = String.valueOf(false)));
Expand All @@ -77,6 +106,63 @@ private class LoggerEngineDataSelector_Tests {
System.Assert.isNull(returnedAuthSessionProxy);
}

@IsTest
static void it_returns_null_when_querying_network_is_disabled() {
LoggerParameter.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryNetworkData', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_NETWORK_DATA);
Id someNetworkId = System.UserInfo.getUserId();
System.Assert.areEqual(0, System.Limits.getQueries());

LoggerSObjectProxy.Network returnedNetworkProxy = LoggerEngineDataSelector.getInstance().getCachedNetworkProxy(someNetworkId);

System.Assert.areEqual(0, System.Limits.getQueries());
System.Assert.isNull(returnedNetworkProxy);
}

@IsTest
static void it_returns_null_when_network_id_is_null() {
System.Assert.isTrue(LoggerParameter.QUERY_NETWORK_DATA);
Id someNetworkId;
System.Assert.areEqual(0, System.Limits.getQueries());

LoggerSObjectProxy.Network returnedNetworkProxy = LoggerEngineDataSelector.getInstance().getCachedNetworkProxy(someNetworkId);

Integer expectedQueryCount = LoggerEngineDataSelector.IS_EXPERIENCE_CLOUD_ENABLED ? 1 : 0;
System.Assert.areEqual(expectedQueryCount, System.Limits.getQueries());
System.Assert.isNull(returnedNetworkProxy);
}

@IsTest
static void it_returns_cached_network_proxy_when_populated_in_cache() {
System.Assert.isTrue(LoggerParameter.QUERY_NETWORK_DATA);
System.Assert.areEqual(0, System.Limits.getQueries());
LoggerEngineDataSelector.useMocks();
LoggerSObjectProxy.Network mockNetworkProxy = new LoggerSObjectProxy.Network();
mockNetworkProxy.Id = System.UserInfo.getUserId();
LoggerCache.getOrganizationCache().put('Network' + mockNetworkProxy.Id, mockNetworkProxy);

LoggerSObjectProxy.Network returnedNetworkProxy = LoggerEngineDataSelector.getInstance().getCachedNetworkProxy(mockNetworkProxy.Id);

System.Assert.areEqual(0, System.Limits.getQueries());
System.Assert.areEqual(mockNetworkProxy, returnedNetworkProxy);
}

@IsTest
static void it_returns_mock_network_proxy_when_mock_is_provided() {
System.Assert.isTrue(LoggerParameter.QUERY_NETWORK_DATA);
System.Assert.areEqual(0, System.Limits.getQueries());
LoggerEngineDataSelector.useMocks();
LoggerSObjectProxy.Network mockNetworkProxy = new LoggerSObjectProxy.Network();
mockNetworkProxy.Id = System.UserInfo.getUserId();
LoggerEngineDataSelector.mockNetworkProxies.add(mockNetworkProxy);

LoggerSObjectProxy.Network returnedNetworkProxy = LoggerEngineDataSelector.getInstance().getCachedNetworkProxy(mockNetworkProxy.Id);

Integer expectedQueryCount = LoggerEngineDataSelector.IS_EXPERIENCE_CLOUD_ENABLED ? 1 : 0;
System.Assert.areEqual(expectedQueryCount, System.Limits.getQueries());
System.Assert.areEqual(mockNetworkProxy, returnedNetworkProxy);
}

@IsTest
static void it_returns_cached_organization() {
Schema.Organization expectedOrganization = [
Expand Down
4 changes: 2 additions & 2 deletions sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"definitionFile": "./config/scratch-orgs/base-scratch-def.json",
"scopeProfiles": true,
"versionNumber": "4.15.2.NEXT",
"versionName": "Improved Testability of Query Selectors",
"versionDescription": "Tweaked the internals of the selector classes to provide more control & reusability to improve overall testability",
"versionName": "Improved Testability of Queries",
"versionDescription": "Enhanced the internals of the existing selector classes LoggerEngineDataSelector and LogManagementDataSelector + introducted a new class LoggerConfigurationSelector to provide improve testability of queries",
"releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases",
"unpackagedMetadata": {
"path": "./nebula-logger/extra-tests"
Expand Down

0 comments on commit 5520135

Please sign in to comment.