afv-library/skills/platform-data-manage/assets/cleanup/delete-test-data.apex

312 lines
17 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ═══════════════════════════════════════════════════════════════════════════════
* DELETE TEST DATA - COMPREHENSIVE CLEANUP
* Remove all test data matching common test data patterns
* ═══════════════════════════════════════════════════════════════════════════════
*
* PURPOSE:
* Clean up test data created by TestDataFactory classes.
* Targets common test data naming patterns across multiple objects.
*
* PATTERNS MATCHED:
* • 'Test%' - Standard test prefix
* • 'BulkTest%' - Bulk testing data
* • 'BatchTest%' - Batch Apex testing data
* • 'BulkData%' - Large volume test data
* • 'BulkImport%' - Import testing data
* • 'Hierarchy%' - Hierarchy testing data
* • '%@testfactory.example.com' - Test email domain
* • '%@bulktest.example.com' - Bulk test email domain
*
* ═══════════════════════════════════════════════════════════════════════════════
*/
// ═══════════════════════════════════════════════════════════════════════════════
// CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════════
Boolean previewOnly = true; // Set to false to actually delete
Integer maxRecordsPerObject = 10000;
// Patterns to match (add your custom test patterns here)
List<String> namePatterns = new List<String>{
'Test%',
'BulkTest%',
'BatchTest%',
'BulkData%',
'BulkImport%',
'Hierarchy%'
};
List<String> emailPatterns = new List<String>{
'%@testfactory.example.com',
'%@bulktest.example.com',
'%@batchtest.example.com'
};
// ═══════════════════════════════════════════════════════════════════════════════
// TRACKING
// ═══════════════════════════════════════════════════════════════════════════════
Map<String, Integer> recordCounts = new Map<String, Integer>();
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('COMPREHENSIVE TEST DATA CLEANUP');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('Mode: ' + (previewOnly ? 'PREVIEW ONLY' : '⚠️ DELETE MODE'));
System.debug('Patterns: ' + namePatterns);
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 1: FIND TASKS (delete first - activity records)
// ═══════════════════════════════════════════════════════════════════════════════
List<Task> tasksToDelete = [
SELECT Id, Subject, WhoId, WhatId
FROM Task
WHERE Subject LIKE 'Test%'
OR Subject LIKE 'BulkTest%'
OR Subject LIKE 'Hierarchy%'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Task', tasksToDelete.size());
System.debug('📋 Tasks found: ' + tasksToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 2: FIND EVENTS
// ═══════════════════════════════════════════════════════════════════════════════
List<Event> eventsToDelete = [
SELECT Id, Subject, WhoId, WhatId
FROM Event
WHERE Subject LIKE 'Test%'
OR Subject LIKE 'All Day Event%'
OR Subject LIKE 'Recurring Event%'
OR Subject LIKE 'Calendar Event%'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Event', eventsToDelete.size());
System.debug('📋 Events found: ' + eventsToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 3: FIND CASES
// ═══════════════════════════════════════════════════════════════════════════════
List<Case> casesToDelete = [
SELECT Id, Subject, AccountId
FROM Case
WHERE Subject LIKE 'Test%'
OR Subject LIKE 'Hierarchy Case%'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Case', casesToDelete.size());
System.debug('📋 Cases found: ' + casesToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 4: FIND OPPORTUNITIES
// ═══════════════════════════════════════════════════════════════════════════════
List<Opportunity> opportunitiesToDelete = [
SELECT Id, Name, AccountId
FROM Opportunity
WHERE Name LIKE 'Test%'
OR Name LIKE 'BulkTest%'
OR Name LIKE 'BatchTest%'
OR Name LIKE 'Hierarchy%'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Opportunity', opportunitiesToDelete.size());
System.debug('📋 Opportunities found: ' + opportunitiesToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 5: FIND CONTACTS
// ═══════════════════════════════════════════════════════════════════════════════
List<Contact> contactsToDelete = [
SELECT Id, FirstName, LastName, Email, AccountId
FROM Contact
WHERE LastName LIKE 'Contact_%'
OR LastName LIKE 'Hierarchy%'
OR LastName LIKE 'Test%'
OR Email LIKE '%@testfactory.example.com'
OR Email LIKE '%@bulktest.example.com'
OR Email LIKE '%@batchtest.example.com'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Contact', contactsToDelete.size());
System.debug('📋 Contacts found: ' + contactsToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 6: FIND LEADS
// ═══════════════════════════════════════════════════════════════════════════════
List<Lead> leadsToDelete = [
SELECT Id, FirstName, LastName, Company
FROM Lead
WHERE LastName LIKE 'Lead%'
OR LastName LIKE 'Test%'
OR Company LIKE 'Test Company%'
OR Email LIKE '%@testlead.example.com'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Lead', leadsToDelete.size());
System.debug('📋 Leads found: ' + leadsToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 7: FIND ACCOUNTS (delete last - parent records)
// ═══════════════════════════════════════════════════════════════════════════════
List<Account> accountsToDelete = [
SELECT Id, Name
FROM Account
WHERE Name LIKE 'Test%'
OR Name LIKE 'BulkTest%'
OR Name LIKE 'BatchTest%'
OR Name LIKE 'BulkData%'
OR Name LIKE 'BulkImport%'
OR Name LIKE 'Hierarchy%'
OR Name LIKE 'Root Account%'
OR Name LIKE 'Level%'
LIMIT :maxRecordsPerObject
];
recordCounts.put('Account', accountsToDelete.size());
System.debug('📋 Accounts found: ' + accountsToDelete.size());
// ═══════════════════════════════════════════════════════════════════════════════
// SUMMARY
// ═══════════════════════════════════════════════════════════════════════════════
Integer totalRecords = 0;
for (String objName : recordCounts.keySet()) {
totalRecords += recordCounts.get(objName);
}
System.debug('');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('CLEANUP SUMMARY');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug(' Tasks: ' + recordCounts.get('Task'));
System.debug(' Events: ' + recordCounts.get('Event'));
System.debug(' Cases: ' + recordCounts.get('Case'));
System.debug(' Opportunities: ' + recordCounts.get('Opportunity'));
System.debug(' Contacts: ' + recordCounts.get('Contact'));
System.debug(' Leads: ' + recordCounts.get('Lead'));
System.debug(' Accounts: ' + recordCounts.get('Account'));
System.debug(' ─────────────────────────────────');
System.debug(' TOTAL: ' + totalRecords);
System.debug('═══════════════════════════════════════════════════════════════');
// ═══════════════════════════════════════════════════════════════════════════════
// EXECUTE DELETE
// ═══════════════════════════════════════════════════════════════════════════════
if (!previewOnly && totalRecords > 0) {
System.debug('');
System.debug('⚠️ DELETING RECORDS...');
System.debug(' Deleting in dependency order (children before parents)');
System.debug('');
Integer deletedCount = 0;
// Delete in order: Activities → Children → Parents
try {
if (!tasksToDelete.isEmpty()) {
delete tasksToDelete;
deletedCount += tasksToDelete.size();
System.debug(' ✓ Deleted ' + tasksToDelete.size() + ' Tasks');
}
if (!eventsToDelete.isEmpty()) {
delete eventsToDelete;
deletedCount += eventsToDelete.size();
System.debug(' ✓ Deleted ' + eventsToDelete.size() + ' Events');
}
if (!casesToDelete.isEmpty()) {
delete casesToDelete;
deletedCount += casesToDelete.size();
System.debug(' ✓ Deleted ' + casesToDelete.size() + ' Cases');
}
if (!opportunitiesToDelete.isEmpty()) {
delete opportunitiesToDelete;
deletedCount += opportunitiesToDelete.size();
System.debug(' ✓ Deleted ' + opportunitiesToDelete.size() + ' Opportunities');
}
if (!contactsToDelete.isEmpty()) {
delete contactsToDelete;
deletedCount += contactsToDelete.size();
System.debug(' ✓ Deleted ' + contactsToDelete.size() + ' Contacts');
}
if (!leadsToDelete.isEmpty()) {
delete leadsToDelete;
deletedCount += leadsToDelete.size();
System.debug(' ✓ Deleted ' + leadsToDelete.size() + ' Leads');
}
if (!accountsToDelete.isEmpty()) {
delete accountsToDelete;
deletedCount += accountsToDelete.size();
System.debug(' ✓ Deleted ' + accountsToDelete.size() + ' Accounts');
}
System.debug('');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('✅ CLEANUP COMPLETE');
System.debug(' Deleted: ' + deletedCount + ' records');
System.debug(' Status: Moved to Recycle Bin');
System.debug('═══════════════════════════════════════════════════════════════');
} catch (DmlException e) {
System.debug('');
System.debug('❌ DELETE ERROR: ' + e.getMessage());
System.debug(' Some records may have dependencies preventing deletion.');
System.debug(' Try running again after resolving dependencies.');
}
} else if (previewOnly) {
System.debug('');
System.debug(' PREVIEW MODE - No records deleted');
System.debug(' To delete, set previewOnly = false and run again');
System.debug('');
System.debug(' ⚠️ Please review the counts above before deleting!');
}
// ═══════════════════════════════════════════════════════════════════════════════
// BATCH APEX VERSION (For very large datasets)
// ═══════════════════════════════════════════════════════════════════════════════
/*
For datasets larger than 10,000 records, use batch Apex:
public class TestDataCleanupBatch implements Database.Batchable<SObject> {
private String objectName;
private String query;
public TestDataCleanupBatch(String objName, String soqlQuery) {
this.objectName = objName;
this.query = soqlQuery;
}
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(query);
}
public void execute(Database.BatchableContext bc, List<SObject> records) {
delete records;
}
public void finish(Database.BatchableContext bc) {
System.debug('Cleanup complete for ' + objectName);
}
}
// Execute for each object (in order):
Database.executeBatch(new TestDataCleanupBatch('Task',
'SELECT Id FROM Task WHERE Subject LIKE \'Test%\''), 200);
Database.executeBatch(new TestDataCleanupBatch('Account',
'SELECT Id FROM Account WHERE Name LIKE \'Test%\''), 200);
*/