-
-
Save mjgallag/1876995 to your computer and use it in GitHub Desktop.
| global class SystemAbortJobMixedDmlBug implements Schedulable { | |
| global void execute(SchedulableContext schedulableContext) {} | |
| } |
| @isTest class SystemAbortJobMixedDmlBugTests { | |
| @isTest static void abortJobNoDmlTest() { | |
| final Id cronTriggerId = System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| System.assertEquals(1, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| System.abortJob(cronTriggerId); | |
| System.assertEquals(0, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| } | |
| // this is technically valid behavior, and not a bug, but, an ideal solution to the bug in the next test case below would be System.abortJob just working with mixed DML | |
| @isTest static void abortJobBeforeDmlTest() { | |
| final Account testAccount = new Account(Name = 'Test'); | |
| final Id cronTriggerId = System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| System.assertEquals(1, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| System.abortJob(cronTriggerId); | |
| try { | |
| insert testAccount; | |
| System.assert(false); | |
| } | |
| catch (DmlException mixedDmlException) { | |
| System.assertEquals(StatusCode.MIXED_DML_OPERATION, mixedDmlException.getDmlType(0)); | |
| System.assertEquals( | |
| 'DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Account, original object: CronJobDetail', | |
| mixedDmlException.getDmlMessage(0) | |
| ); | |
| } | |
| System.assertEquals(0, [SELECT COUNT() FROM Account WHERE Id = :testAccount.Id]); | |
| System.assertEquals(0, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| } | |
| // BUG: this should be throwing the same mixed DML exception as above, or just work, instead of silently NOT aborting the job | |
| @isTest static void abortJobAfterDmlTest() { | |
| final Account testAccount = new Account(Name = 'Test'); | |
| final Id cronTriggerId = System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| System.assertEquals(1, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| insert testAccount; | |
| System.abortJob(cronTriggerId); | |
| System.assertEquals(1, [SELECT COUNT() FROM Account WHERE Id = :testAccount.Id]); | |
| System.assertEquals(1, [SELECT COUNT() FROM CronTrigger WHERE Id = :cronTriggerId]); | |
| try { | |
| System.schedule('SystemAbortJobMixedDmlBug', '0 0 * * * ?', new SystemAbortJobMixedDmlBug()); | |
| } | |
| catch (AsyncException scheduleAsyncException) { | |
| System.assertEquals('The Apex job named "SystemAbortJobMixedDmlBug" is already scheduled for execution.', scheduleAsyncException.getMessage()); | |
| } | |
| } | |
| } |
Wow, that's really weird. Hopefully Rich has some insight. My hunch: the abortJob docs say "Stops the specified job. The stopped job is still visible in the job queue in the Salesforce user interface.", which makes me think it just changes that status, and doesn't actually delete the job.
When I tried my more limited version I had abortJob and a new scheduled job as the only DML in my scheduled class' finish method, which sounds like the reason I never hit this issue.
I just clarified the test cases a bit, most notably, showing that in the abortJobAfterDmlTest() test case, the job is most definitely not aborted as an exception is thrown if you try to reschedule it. I'm going to assume this bug will be fixed by simply throwing a mixed dml exception in both cases, instead of just one, and hope it's fixed to allow abort job to work without causing a mixed dml exception at all :)
Makes me want to go back to the days when Custom Settings were Setup Objects (API <= 17.0), since that's what I was trying to perform DML on in my specific case.