Locking, and How to Test it

This is a two part question. Which type of locking should I use
(optimistic vs. pessimistic) and then how do I account for locking in
my tests?

My scenario is essentially the purchase of a unique item where the
first person to click "Buy" gets the item and everyone else is out of
luck. As a single transaction, I need to determine whether the item
has already been purchased; if so provide an error message, otherwise
buy it. If I did not lock, race conditions may lead multiple people
to think they were succesful (and it would make a mess out of my
otherwise simple accounting).

I'm leaning towards optimistic because: 1) my rails app is the only
thing touching the DB, 2) I'm trying to remain agnostic on DB software
for now, but 3) I don't really want a read-lock. Am I overlooking
anything that might push me in the other direction?

For testing, I'm trying to be a good TDD citizen, so exactly what test
would cause me to write the logic to handle
ActiveRecord::StaleObjectError? (Or if I go with pessimistic,
the :lock => true option) Considering the record is located, updated,
and saved by the same method I can't think of a good way to actually
cause the race condition for a test. But common sense tells me it
will happen frequently once I have multiple users interacting with the

for optimistic locking,

It can be quite handy to just mock save! and have it throw
StaleObjectError. depending on your code you may also be able to do

firstInstance = SomeModel.find 1
secondInstance = SomeModel.find 1
secondInstance.created_at_will_change! #or anything that will make the
save not be a no-op

#do something with firstInstance (it is now stale)

Pessimistic locking is a little different - not much will change for
your code except that a select or a write may just block for a little
longer than usual. You should be prepared to handle whatever your
database does if it times out getting a lock or detects a deadlock.


Ah, great idea. So in the absence of a mock object framework*, is
something like the following fairly standard?

    MyModel.send(:define_method, :save!) { raise
ActiveRecord::StaleObjectError, "Boom!" }
    ... #test handling of race condition here
    MyModel.send(:undef, :save!)

Since "save!" is inherited, I don't think I need to worry about
aliasing the old one out of the way or anything.

This technique works well. I'm able to reimplement save (or save!) to
simulate pretty much any race condition I want to handle. I ended up
with something like this:

  # mock save to simulate another user getting there first.
  sneaky_user = users(:brian)
  ItemForSale.send(:define_method, :save) do
    buyer = sneaky_user
    raise ActiveRecord::StaleObjectError, "Boom!"

  item = itemsforsale(:vase)
  assert !item.sell_to(users(:allen)) # uses save internally
  assert item.errors.invalid?(:buyer)

  # models aren't reloaded, so I need to clean up
  ItemForSale.send(:undef_method, :save)

Which should work well as a test for this:

def sell_to(user)
  buyer = user

  rescue ActiveRecord::StaleObjectError
    errors.add(:buyer, "already assigned for this item")
    return false