You need to sign in to do that
Don't have an account?
CallMeHugo
Unit testing atomic method execution FOR UPDATE
Hi all,
I have a written a method to allocate MAC addresses based on a custom setting that holds the min, max and current pointer. To make sure I never have duplicates and that the method is atomic, I have use the FOR UPDATE keywords on my query. Now I would like to validate the behaviour using a unit test but I am not able to reproduce multiple queries arriving at the same time to force a collision. Here is some simplified code:
public static String GetMAC() {
string mac;
MACAddressBank__c bank = [SELECT CurrentMAC__c FROM MACAddressBank__c FOR UPDATE];
mac = bank.CurrentMAC__c;
bank.CurrentMAC__c++; // Assuming you can do this - for simplicity of the example
UPDATE bank;
}
//// Test
static testMethod void Test_ValidateCollisionMACBank() {
INSERT new MACAddressBank__c(Name = 'bank1', CurrentMAC__c = '0123456789AB' );
Test.startTest();
Integer size = 1000;
// Create asynchhronous requests that will retreive macs at the same time
RequestMACBatchAsync( MAClist1, size );
RequestMACBatchAsync( MAClist2, size );
RequestMACBatchAsync( MAClist3, size );
RequestMACBatchAsync( MAClist4, size );
Test.stopTest(); // Wait for async methods to finish
// Do some logic with asserts and check if all lists contains consecutive MACs
=> Always true, !!! Should not, I want to reproducr collision!
// Do some logic to check if duplicates exists across each lists
=> Always false, OK
}
static List<String> MAClist1 = new List<String>();
static List<String> MAClist2 = new List<String>();
static List<String> MAClist3 = new List<String>();
static List<String> MAClist4 = new List<String>();
@future
private static void RequestMACBatchAsync( List<String> macs, Integer qty ) {
while( macs.size() < qty ) {
macs.add(GetMAC());
}
}
So the problem is that I am not able to reproduce two calls to GetMAC at the same time.
I also tried to modify the GetMAC method to retreive a fair amount of MACs at the same time but the test always return consecutive MACs in each lists.
This is a business critical process and major problems can happen if a MAC is duplicated for the end user. I really want to make sure that my lock is working correctly. Any ideas on how I can mock this?
Thanks.
I have a written a method to allocate MAC addresses based on a custom setting that holds the min, max and current pointer. To make sure I never have duplicates and that the method is atomic, I have use the FOR UPDATE keywords on my query. Now I would like to validate the behaviour using a unit test but I am not able to reproduce multiple queries arriving at the same time to force a collision. Here is some simplified code:
public static String GetMAC() {
string mac;
MACAddressBank__c bank = [SELECT CurrentMAC__c FROM MACAddressBank__c FOR UPDATE];
mac = bank.CurrentMAC__c;
bank.CurrentMAC__c++; // Assuming you can do this - for simplicity of the example
UPDATE bank;
}
//// Test
static testMethod void Test_ValidateCollisionMACBank() {
INSERT new MACAddressBank__c(Name = 'bank1', CurrentMAC__c = '0123456789AB' );
Test.startTest();
Integer size = 1000;
// Create asynchhronous requests that will retreive macs at the same time
RequestMACBatchAsync( MAClist1, size );
RequestMACBatchAsync( MAClist2, size );
RequestMACBatchAsync( MAClist3, size );
RequestMACBatchAsync( MAClist4, size );
Test.stopTest(); // Wait for async methods to finish
// Do some logic with asserts and check if all lists contains consecutive MACs
=> Always true, !!! Should not, I want to reproducr collision!
// Do some logic to check if duplicates exists across each lists
=> Always false, OK
}
static List<String> MAClist1 = new List<String>();
static List<String> MAClist2 = new List<String>();
static List<String> MAClist3 = new List<String>();
static List<String> MAClist4 = new List<String>();
@future
private static void RequestMACBatchAsync( List<String> macs, Integer qty ) {
while( macs.size() < qty ) {
macs.add(GetMAC());
}
}
So the problem is that I am not able to reproduce two calls to GetMAC at the same time.
I also tried to modify the GetMAC method to retreive a fair amount of MACs at the same time but the test always return consecutive MACs in each lists.
This is a business critical process and major problems can happen if a MAC is duplicated for the end user. I really want to make sure that my lock is working correctly. Any ideas on how I can mock this?
Thanks.
See the blog below which has good code,
Here is the apex test class, if you want to experiment.
public class TestRecordLocking {
testmethod public static void testLocking() {
// create a account from logged in user
Account accoutU1 = new Account(Name = 'Abhinav Gupta');
insert accoutU1;
// lock the same account
accoutU1 = [Select Id, Name, Website from Account where Id =:accoutU1.id for update];
//Start updating it
accoutU1.website = 'www.salesforce.com';
// Now lets say, some other user comes and tries to update the same record
User u2 = [Select Id from user where id !=:UserInfo.getUserId() limit 1];
System.runAs(u2) {
// other user queries the same account
Account accountU2 = [Select Id, Name, Website from Account where Id =:accoutU1.id ];
// other user tries to update it
accountU2.WebSite = 'www.yahoo.com';
update accountU2;
}
// Now update the original account back.
update accoutU1;
}
}
http://www.tgerm.com/2011/04/visualizing-record-locking-in-soql-ie.html
Regards,
Ashish