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!"
  end

  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

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

On Jul 12, 9:02 pm, Brian <butler.bria...@gmail.com> wrote:
> 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.
>
> On Jul 12, 8:38 pm, Frederick Cheung <frederick.che...@gmail.com>
> wrote:
>
>
>
> > On Jul 13, 1:04 am, Brian <butler.bria...@gmail.com> wrote:
>
> > > 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
> > > app.
>
> > 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
> > secondInstance.save!
>
> > #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.
>
> > Fred- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> - Show quoted text -
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to rubyonrails-talk@googlegroups.com
To unsubscribe from this group, send email to 
rubyonrails-talk+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to