Today, I came across this interesting tweet.
Luckily I knew the answer, and found the same in apex docs too i.e.
“While an sObject record is locked, no other program or user is allowed to make updates.”
But a “t” germ inside me provoked to test this out and create a POC to see “FOR UPDATE” in action, I want to see what crash/error comes, when one attempts to update a locked record from other user !
So, I tried to create a multi-user scenario updating same locked records in various ways like
Visualforce page & Apex Controller
Apex Test class to simulate two users
Failed approach – Visualforce page & Apex Controller
I created a visualforce page that does a lot of things after locking some Account records. These lot of things include: call outs, iterating nearly 1,90,000 times to add extra delay and still stay out of governor attacks. But this can’t succeed as it was really next to impossible to time two users in two browsers hit the page at exact same interval. So dumped this silly experiment, without wasting any more time #@$#$
Apex test class to simulate two users – need your views here !
Create an Apex test class that tries to simulate the same using System.runAs().
My use case(scenario) was to create a test method in this class that :
Creates an account from the logged in user.
Query that same account back using “for update”.
Start new context using “System.runAs()” from some other user i.e. not the logged in user.
Try updating the same locked account, using that other simulation user.
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;
}
}
Expected Result on Executing this Apex Test ?
It should fail, isn’t ? As I am trying to update record locked by some other user. Unfortunately it works like a charm. I believe, System.runAs() is not creating exact multi user context that might be created in real life ?
Please let me know your views and ideas on this ?
Comments (6)
Anonymoussays:
April 13, 2011 at 12:38 pmYou're working as two separate users, but in one transaction. RunAs does not create a new transaction. So, all the updates are utilizing the same lock.
Anonymoussays:
April 13, 2011 at 12:46 pmHi Abhinav, which specific line fails? 16 or 19?
Anonymoussays:
April 13, 2011 at 12:50 pmSorry misread, thought you said it failed.
Anonymoussays:
April 13, 2011 at 1:32 pmThanks @Rich, your point seems valid, System.runAs() is not starting new transaction. How can we see this in action, any other better way to reproduce it.Hey @richardvanhook, looking for your inputs too..
Anonymoussays:
April 13, 2011 at 5:58 pmI've seen it happen often by accident, for example by having a test that locks records, and then seeing errors in non-test requests. (Good reason to keep test data separate, BTW.) Not sure how you'd reproduce this 100% of the time though.
Anonymoussays:
April 14, 2011 at 5:56 amYeah, running long test is a good example.For sure, test data should be separate from user data, I believe here salesforce needs to provide this isolation, I really don't see any cases where one will need user data in test cases, all of the stuff like customsetting/records can be created in test case.