+ Start a Discussion
John Gorzynski 1John Gorzynski 1 

Testing the Accept Button


I recently created a trigger on Case that updates a couple custom fields when the Case Owner changes.  It works great, except when a User uses the Accept button to change the ownership from a Queue to their account.  When this happens, the trigger executes twice.  I need to catch this behavior and make sure the trigger logic only executes once, but I cannot figure out how to mimic the "Accept" button in my Apex Text Class. 

There are two ways I hope this community could help me:
1) How can I get the Developer Console to generate logs based on my actions using clicks within SF, rather than just from running tests within the developer's console?
2) Or, how can I mimic the 'Accept' button in an Apex test?

Thank you!
-John Gorzynski

Trigger Code:

trigger CaseOwnerChangeEscalation on Case (after insert, before update) {  //, before update

 * Written by:  John Gorzynski 
 * 				June 04, 2015
 * This trigger looks at new and modified Cases and sets the GSCC_Queue__c field in order to track Escalations.
 * STEP 1) Determine if the Record Type is a Support Services Case, or if a change in Case Owner or Oracle_SR_Owner_Name__c has occurred.  Only process these cases.
 * STEP 2) Process all Case changes, collect User and Group (Queue) IDs to find the correct value for GSCC_Queue__c
 * 		-) If Owner is Group, use Group.Name.    If Owner is User, use User.GSCC_Queue__c, which is set by Formula Field on the Users table.
 * STEP 3) Once Cases have been updated, check if they moved from Tier 1 to Tier 2 or Tier 3.  If so, increment Case.Escalation_Count__c
 * 		-) If an Escalation happened, add a Case Comment with the User who updated the ticket, regardless of queue, and what Tier change or Tier 3 group assignment occurred. 
 * **************************/
/*** Step 1:  Identify Support Services Cases where the Case Owner or Oracle_SR_Owner_Name__c has changed.  Ignore all others.***/
    System.debug('[Trigger Start]');
        List<Case> caseList = new List<Case>();
        List<Case> oldCases = new List<Case>();
    	List<Case> newCases = new List<Case>();
        List<Group> groupList = new List<Group>();
        List<User> userList = new List<User>();
        Set<Id> ownerIds = new Set<Id>();
    	Set<Id> Tier3Ids = new Set<Id>();
    	Set<Id> rt = new Set<Id>();
    		for(Case ci : [SELECT Id, OwnerId, Escalation_Count__c, Oracle_SR_Owner_Name__c, GSCC_Queue__c, RecordTypeId FROM Case WHERE ID IN :Trigger.New]) 
            {   newCases.add(ci);   }
            for(Case cu : Trigger.New)  
            {  newCases.add(cu);  }    
    	//Grab all Record Types that include Support Services in the Name field.  Only run trigger on cases with these RecordTypeIds.
   		for(RecordType rec : [Select Id, Name FROM RecordType WHERE Name LIKE '%Support Services%'])
        {  rt.add(rec.Id);  }
    	//Filter cases by those with an owner change or Tier 3 change, but only for Support Services cases.
        for(Case c : newCases) 
            //Set beforeUpdate so Trigger.isInsert will avoid a Null Pointer exception.
            Case beforeUpdate = (Trigger.isUpdate) ? System.Trigger.oldMap.get(c.Id) : new Case(); 
            String oldTier3 = (beforeUpdate.Oracle_SR_Owner_Name__c!=NULL) ? beforeUpdate.Oracle_SR_Owner_Name__c : '';
            String newTier3 = (c.Oracle_SR_Owner_Name__c!=NULL) ? c.Oracle_SR_Owner_Name__c : '';
            Boolean isOwnerChange = (beforeUpdate.OwnerID != c.OwnerID);  //OwnerID Should never be null
            Boolean isTier3Change = (oldTier3 != newTier3);
            Boolean isTier3 = (c.Oracle_SR_Owner_Name__c!=NULL);  //We only want Tier3 changes to trigger, but always use Tier 3 if set.
            Boolean isSupportRT = false;

                String newRT = (c.RecordTypeId==NULL) ? '' : c.RecordTypeId;
            	isSupportRT = rt.contains(newRT);  //True if Record Type contains 'Support Services'
            catch (Exception e) { isSupportRT = false; }  //Throws a String Exception: Invalid ID if RecordTypeId is not set.

            System.debug('[Pre-Trigger] Old Trigger: GSCC_Queue__c:'+beforeUpdate.GSCC_Queue__c+' | OwnerID:'+beforeUpdate.OwnerID+' | Oracle_SR_Owner_Name__c:'+beforeUpdate.Oracle_SR_Owner_Name__c+' | Escalation_Count__C:'+beforeUpdate.Escalation_Count__C+' ||| New Trigger: GSCC_Queue__c:'+c.GSCC_Queue__c+' | OwnerID:'+c.OwnerID+' | Oracle_SR_Owner_Name__c:'+c.Oracle_SR_Owner_Name__c+' | Escalation_Count__C:'+c.Escalation_Count__C);
               Decimal newEscalation = (c.Escalation_Count__c!=NULL) ? c.Escalation_Count__c : 0;
               c.Escalation_Count__c = newEscalation; 
               System.debug('[Trig Test]: c.Escalation_Count__c:'+c.Escalation_Count__c+' newEscalation:'+newEscalation);
               if(!isTier3) ownerIds.add(c.ownerId);  //We don't need OwnerID if Tier 3 is set
               if(isTier3) Tier3Ids.add(c.Id);               
            if(!isSupportRT)  System.debug('[Pre-Trigger] Case.RecordType does not include Support Services');  

        System.debug('[Trig] caseList.size():'+caseList.size()+' = OwnerIDs:'+OwnerIds.size()+' + Tier3Ids:'+Tier3Ids.size());

/*** Step 2:  For valid Case updates, determine what field changed and set GSCC_Queue__c:
	 -) If new CaseOwner is a Queue, set to Group.name;
	 -) If new CaseOwner is a User, set to User.GSCC_Queue__c (set by Formula Field on User object)
	 -) If Oracle_SR_Owner_Name__c is set, ignore any CaseOwner change and use that value for Tier 3.
            System.debug('[Trig] Cases have recent updates, processing Trigger.');
            for(Group g : [SELECT Id, Name FROM Group WHERE Id IN :ownerIds]){ 
                if(g.Name==NULL) g.Name = ''; 
                    System.debug('[Trig] groupList.size():'+groupList.size());
            for(User u : [SELECT Id,Name,GSCC_Queue__c FROM User WHERE Id IN :ownerIds]){ 
                if(u.GSCC_Queue__c==NULL) u.GSCC_Queue__c = '';  //Prevents Null Pointer Exception if GSCC_Queue__c is not set.
                     System.debug('[Trig] userList.size():'+userList.size());
            //If CaseOwner is a Queue, Assign Queue.Name to Case.GSCC_Queue__c
            for(Integer i = 0; i < caseList.size();i++){
               if((caseList[i].OwnerId.getSobjectType() == Group.sobjecttype)&&!(Tier3Ids.contains(caseList[i].Id))){
                   for(Integer k=0; k < groupList.size();k++){
                       if(caseList[i].OwnerId == groupList[k].Id){
                            caseList[i].GSCC_Queue__c = groupList[k].Name;
            	//If CaseOwner is a User, Assign User.GSCC_Queue__c to Case.GSCC_Queue__c
           		//User.GSCC_Queue__c is set manually per Agent in a Formula Field on the User table.
                if((caseList[i].OwnerId.getSobjectType() == User.sobjecttype)&&!(Tier3Ids.contains(caseList[i].Id))){
                    for(Integer m=0; m < userList.size(); m++){
                         if(caseList[i].OwnerId == userList[m].Id){
                            caseList[i].GSCC_Queue__c = userList[m].GSCC_Queue__c;
                System.debug('[Trig: Assignment Complete] caseList['+i+']: Id:'+caseList[i].Id+' | GSCC_Queue__c:'+caseList[i].GSCC_Queue__c+' | Oracle_SR_Owner_Name__c:'+caseList[i].Oracle_SR_Owner_Name__c+' | Escalation_Count__c:'+caseList[i].Escalation_Count__c);
					caseList[i].GSCC_Queue__c = (caseList[i].Oracle_SR_Owner_Name__c.contains('Tier 3')) ? caseList[i].Oracle_SR_Owner_Name__c : 'Tier 3 '+caseList[i].Oracle_SR_Owner_Name__c; 
            } //End for loops for setting c.GSCC_Queue__c

/*** Step 3:  If Tier level has increased, increment Case.Escalation_Count__c. and add a Case Comment***/            
            for(Integer j = 0; j < caseList.size();j++){
                String oldQueue = (oldCases[j].GSCC_Queue__c!=NULL) ? oldCases[j].GSCC_Queue__c : '[No GSCC Tier Set]';
                String newQueue = (caseList[j].GSCC_Queue__c!=NULL) ? caseList[j].GSCC_Queue__c : '[No GSCC Tier Set]';
                datetime myDateTime = datetime.now();
                //If GSCC_Queue__c has changed Tier, escalate the case and add a Case Comment
                if((oldQueue.contains('Tier 1')&&newQueue.contains('Tier 2'))||
                   (oldQueue.contains('Tier 2')&&newQueue.contains('Tier 3'))||
                   (oldQueue.contains('Tier 1')&&newQueue.contains('Tier 3'))||
                   (oldQueue=='[No GSCC Tier Set]'&&newQueue.contains('Tier 2'))||
                   (oldQueue=='[No GSCC Tier Set]'&&newQueue.contains('Tier 3'))) 
                    { caseList[j].Escalation_Count__c += 1; 
                      system.debug('[Trig] CaseList['+j+'] Escalated - Escalation_Count__c:'+caseList[j].Escalation_Count__c+', Id:'+ caseList[j].id);
                      CaseComment com = new CaseComment();
                      TimeZone tz = UserInfo.getTimeZone();
                      String strConvertedDate = myDateTime.format('MMMM dd, yyyy hh:mm:ss a z', tz.getId());
                      com.ParentId = caseList[j].id;  
                      com.CommentBody = 'This case was escalated by '+ UserInfo.getName() +' from '+oldQueue+' to '+newQueue+' on '+strConvertedDate;
                      system.debug('[Trig] Case Comment:'+com.CommentBody);
                      Insert com;
            { update caseList; }
        } //End If: caseList.size()>0 or isInsert

Test Code:

@isTest static void TestEscalationByOracleSRNameChange() {
         //Test Queues and Users have had their values chosen to run ten tests:
            //0) Tier 1 Nav (Tier3 set) -> Tier 2 Nav (Tier 3 No Change)	Result:  Escalation:1   Setting to Tier 2 should be ignored.                                 
			//1) Tier 2 Nav 	        -> Tier 2 Nav (Tier 3 set)    		Result:  Escalation:2   Escalates on Insert to Tier 2 And when Tier 3 is set.  
			//2) Tier 1 Ops (Tier3 set) -> Tier 1 Nav (Tier 3 Change) 		Result:  Escalation:1   Changes within Tier 3 are not another Escalation.
			//3) Tier 2 Ops (Tier3 set) -> Tier 2 Nav (Tier 3 No Change)    Result:  Escalation:1   Setting to Tier 2 should be ignored.
			//4) Record Type set to Professional Services					Result:  No change
			//5) Professional Services w/ Tier 2 Owner + Tier 3 set			Result:  No change, but Oracle_SR_Owner_Name__c was still set.    
		//Cases will first be assigned the the Queue List, and then updated to the Owner List to run these tests.
        List<Case> cList2 = new List<Case>(); 
        List<ID> QownIDs = new ID[6];
        List<ID> UownIDs = new ID[6];
        List<QueueSobject> mappingObjects = new List<QueueSobject>();

        RecordType rt = [Select Id from RecordType where Name = 'Support Services NAV Case' LIMIT 1]; 
        RecordType rt2 = [Select Id from RecordType where Name = 'Professional Services Case' LIMIT 1];

        List<Group> gList = new List<Group> {
             new Group(Name='Tier 1 GSCC NAV ',Type='Queue'),
             new Group(Name='Tier 2 GSCC NAV ',Type='Queue'),
             new Group(Name='Tier 1 GSCC OPS ',Type='Queue'),
             new Group(Name='Tier 2 GSCC OPS ',Type='Queue'),
             new Group(Name='Tier 1 GSCC NAV ',Type='Queue'),
             new Group(Name='Tier 2 GSCC NAV ',Type='Queue')};
         //Insert Queues
         System.runAs(new User(Id = UserInfo.getUserId())) { insert gList; }
         for(Integer i=0; i < gList.size(); i++){ 
            QueueSobject mapObj = new QueueSobject(QueueId = gList[i].Id, SobjectType = 'Case');  
          //Insert Queue Relational Maps
         System.runAs(new User(Id = UserInfo.getUserId())) { insert mappingObjects; }

        List<User> uList = new List<User> {   //createUser generates a User object with all required fields set.  The first parameter gives unique names.  The second parameter is set to GSCC_Queue__c.
			createUser(1,'Tier 2 GSCC NAV'),
			createUser(2,'Tier 2 GSCC NAV'),
			createUser(3,'Tier 1 GSCC NAV'),
			createUser(4,'Tier 2 GSCC NAV'),
            createUser(5,'Tier 1 GSCC NAV'),
            createUser(6,'Tier 2 GSCC NAV')};

         System.runAs(new User(Id = UserInfo.getUserId())) { insert uList; }
        for(Integer k=0; k < gList.size(); k++){
      			QownIDs[k] = gList[k].ID;
            	UownIDs[k] = uList[k].ID;

        List<case> cList = new List<Case> {
             new Case(OwnerID=QownIDs[0],Subject='Testing Updates',RecordTypeId = rt.Id,Oracle_SR_Owner_Name__c='Tier 3 Group 1',Escalation_Count__c = NULL),
             new Case(OwnerID=QownIDs[1],Subject='Testing Updates',RecordTypeId = rt.Id,Escalation_Count__c = NULL),
             new Case(OwnerID=QownIDs[2],Subject='Testing Updates',RecordTypeId = rt.Id,Oracle_SR_Owner_Name__c='Tier 3 Group 1'',Escalation_Count__c = NULL),
             new Case(OwnerID=QownIDs[3],Subject='Testing Updates',RecordTypeId = rt.Id,Oracle_SR_Owner_Name__c='Tier 3 Group 1'',Escalation_Count__c = NULL),
             new Case(OwnerID=QownIDs[4],Subject='Testing Updates',RecordTypeId = rt2.Id,Escalation_Count__c = NULL),
             new Case(OwnerID=QownIDs[5],Subject='Testing Updates',RecordTypeId = rt2.Id,Escalation_Count__c = NULL)};
        System.debug('pre-test cList[0].id:'+cList[0].Id+' - pre-test gList[0].id:'+gList[0].Id);
        System.debug('pre-test c[0]:'+cList[0]);
        System.debug('pre-test g[0]:'+gList[0]);
        System.debug('[TEST] After Insert Setup'); 
                 List<Database.SaveResult> srList = new List<Database.SaveResult>();
         System.runAs(new User(Id = UserInfo.getUserId())) { srList = Database.insert(cList,false); }

         for (Database.SaveResult sr : srList){
             if(sr.isSuccess()) {
                 //Operation was Successful
             else {
                 //Operation failed, so get all errors
                 for(Database.Error err : sr.getErrors()) {
                     System.debug('Database Error:'+ err.getMessage());
                     System.debug('Fields that affected this error:'+ err.getFields());

/*** afterInsert Tests ***
*	 Trigger will execute twice due to also firing beforeUpdate, 
*	 but the second time should result in a caseList.size() of 0, causing the trigger to end before Steps 2 or 3.***/ 
		List<Case> insertTest = new List<Case>();			
         for( Case ct : [SELECT Id,GSCC_Queue__c,Escalation_Count__c,Oracle_SR_Owner_Name__c FROM Case WHERE Id IN :cList]){

                 System.assertEquals('Tier 3 Group 1', insertTest[0].GSCC_Queue__c);
                 System.assertEquals('Tier 2 GSCC NAV', insertTest[1].GSCC_Queue__c);
                 System.assertEquals('Tier 3 Group 1', insertTest[2].GSCC_Queue__c);
                 System.assertEquals('Tier 3 Group 1', insertTest[3].GSCC_Queue__c);
                 System.assertEquals(NULL, insertTest[4].GSCC_Queue__c);
                 System.assertEquals(NULL, insertTest[5].GSCC_Queue__c);
                 System.assertEquals(1, insertTest[0].Escalation_Count__c);
                 System.assertEquals(1, insertTest[1].Escalation_Count__c);
                 System.assertEquals(1, insertTest[2].Escalation_Count__c);
                 System.assertEquals(1, insertTest[3].Escalation_Count__c);
                 System.assertEquals(NULL, insertTest[4].Escalation_Count__c);
                 System.assertEquals(NULL, insertTest[5].Escalation_Count__c);
                 System.assertEquals('Tier 3 Group 1', insertTest[0].Oracle_SR_Owner_Name__c);
                 System.assertEquals('Tier 3 Group 1', insertTest[2].Oracle_SR_Owner_Name__c);
                 System.assertEquals('Tier 3 Group 1', insertTest[3].Oracle_SR_Owner_Name__c);
/*** afterInsert Tests end ***/
                Integer l=0;
        for(Case c2 : [SELECT Id, GSCC_Queue__c, Escalation_Count__c, OwnerId FROM Case WHERE Subject='Testing Updates']) {
				cList2[1].Oracle_SR_Owner_Name__c='Tier 3 Group 2';
				cList2[2].Oracle_SR_Owner_Name__c='Tier 3 Group 2';
				cList2[5].Oracle_SR_Owner_Name__c='Tier 3 Group 2';

        List<Database.SaveResult> srList2 = new List<Database.SaveResult>();
         System.runAs(new User(Id = UserInfo.getUserId())) { srList2 = Database.Update(cList2,false); }

         for (Database.SaveResult sr2 : srList2){
             if(sr2.isSuccess()) {
                 //Operation was Successful
             else {
                 //Operation failed, so get all errors
                 for(Database.Error err2 : sr2.getErrors()) {
                     System.debug('Database Error:'+ err2.getMessage());
                     System.debug('Fields that affected this error:'+ err2.getFields());
        System.debug('post-test c[0]:'+cList[0]);
        System.debug('post-test cList[0].Id:'+cList[0].Id);
        System.debug('post-test cList[0].GSCC_Queue__c:'+cList[0].GSCC_Queue__c);
/*** beforeUpdate Tests ***
*	 Trigger executes a third time for beforeUpdate ***/
		List<Case> updateTest = new List<Case>();			
         for( Case ct2 : [SELECT Id,GSCC_Queue__c,Escalation_Count__c,Oracle_SR_Owner_Name__c FROM Case WHERE Id IN :cList2]){
            //0) Tier 1 Nav (Tier3 set) -> Tier 2 Nav (Tier 3 No Change)	Result:  Escalation:1   Setting to Tier 2 should be ignored.                                 
			//1) Tier 2 Nav 	        -> Tier 2 Nav (Tier 3 set)    		Result:  Escalation:2   Escalates on Insert to Tier 2 And when Tier 3 is set.  
			//2) Tier 1 Ops (Tier3 set) -> Tier 1 Nav (Tier 3 Change) 		Result:  Escalation:1   Changes within Tier 3 are not another Escalation.
			//3) Tier 2 Ops (Tier3 set) -> Tier 2 Nav (Tier 3 No Change)    Result:  Escalation:1   Setting to Tier 2 should be ignored.
			//4) Record Type set to Professional Services					Result:  No change
			//5) Professional Services w/ Tier 2 Owner + Tier 3 set			Result:  No change, but Oracle_SR_Owner_Name__c was still set.             
         		 System.assertEquals('Tier 3 Group 1', updateTest[0].GSCC_Queue__c);
                 System.assertEquals('Tier 3 Group 2', updateTest[1].GSCC_Queue__c);
                 System.assertEquals('Tier 3 Group 2', updateTest[2].GSCC_Queue__c);
                 System.assertEquals('Tier 3 Group 1', updateTest[3].GSCC_Queue__c);
                 System.assertEquals(NULL, updateTest[4].GSCC_Queue__c);
                 System.assertEquals(NULL, updateTest[5].GSCC_Queue__c);
                 System.assertEquals(1, updateTest[0].Escalation_Count__c);
                 System.assertEquals(2, updateTest[1].Escalation_Count__c);
                 System.assertEquals(1, updateTest[2].Escalation_Count__c);
                 System.assertEquals(1, updateTest[3].Escalation_Count__c);
                 System.assertEquals(NULL, updateTest[4].Escalation_Count__c);
                 System.assertEquals(NULL, updateTest[5].Escalation_Count__c);
                 System.assertEquals('Tier 3 Group 1', updateTest[0].Oracle_SR_Owner_Name__c);         
                 System.assertEquals('Tier 3 Group 2', updateTest[1].Oracle_SR_Owner_Name__c);         
                 System.assertEquals('Tier 3 Group 2', updateTest[2].Oracle_SR_Owner_Name__c);         
                 System.assertEquals('Tier 3 Group 1', updateTest[3].Oracle_SR_Owner_Name__c);         
                 System.assertEquals(NULL, updateTest[4].Oracle_SR_Owner_Name__c);         
                 System.assertEquals('Tier 3 Group 2', updateTest[5].Oracle_SR_Owner_Name__c);      
/*** beforeUpdate Tests end ***/

If you have Dev Console open while you are clicking buttons in SF, you will get logs in Dev Console.  A likely reason that the trigger runs twice would be a Workflow Rule with a Field Update that fires when the owner changes.  The Accept button will change the owner - run the trigger - fire the field update - and run the trigger again.  Some folks like to use a static boolean variable in a helper class to indicate that a trigger has run and use that to avoid a second execution.  I prefer to use a Set of IDs instead.  As I process records in a trigger, I check to see if the record's ID is in the set.  If not, I process the record and add its IDs to the set.  If so, I skip that record.  That way, if the trigger runs twice, I don't process any records that have already been processed.
John Gorzynski 1John Gorzynski 1

Thank you for your response Glyn, it does appear to be due to a Workflow Rule so I'll try to implement a set of IDs to ensure the triggers are only being updated once. 

I was having trouble displaying logs even when in the Dev Console, but I have since figured out that my settings in the Change Log Level were set too high, which was preventing the logs from showing up. 

Thanks again!