views:

160

answers:

1

I have a set of Test::Unit tests for a Rails application. It was developed on OS X under Ruby 1.8.6, Rails 2.3.4.

I'm also using thoughtbot-shoulda 2.10.2.

I'm using standard Rails fixtures, not factories.

I've checked out the project onto a CentOS Linux 5 workstation for another developer to work on. He's running Ruby 1.8.7.

(The app is running on CentOS Linux 5 in production, and it's working fine there.)

On my coworker's CentOS dev machine, all of the unit tests are passing.

However, most, but not all, of the functional tests are erroring out. I've isolated one test (removing all the others from the project) to narrow down the troubleshooting scope.

  context 'on DELETE to :destroy' do
    setup {
      delete(:destroy, { :id => addresses(:mary_publics_address).id }, stans_id)
    }
    should 'delete the address' do
      assert Address.find(:all, :conditions => {
        :id => addresses(:mary_publics_address).id
      } ).blank?
    end
    should 'delete the addresses phone numbers' do
      assert PhoneNumber.find(:all, :conditions => {
        :id => phone_numbers(:mary_publics_phone_number).id
      } ).blank?
    end
  end

The error we're getting is...

[abc@abc contactdb]$ rake test:functionals --trace
(in /home/abc/projects/contactdb)

[ ... ]

/usr/local/ruby_187/bin/ruby -I"lib:test" "/home/abc/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/functional/addresses_controller_test.rb" 
Loaded suite /home/abc/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.E
Finished in 0.426749 seconds.

  1) Error:
test: on DELETE to :destroy should delete the addresses phone numbers. (AddressesControllerTest):
ActiveRecord::RecordNotFound: Couldn't find Address with ID=1254595889
    /test/functional/addresses_controller_test.rb:107:in `__bind_1255114457_160068'
    /usr/local/ruby_187/lib/ruby/gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:369:in `call'
    /usr/local/ruby_187/lib/ruby/gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:369:in `run_current_setup_blocks'
    /usr/local/ruby_187/lib/ruby/gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:368:in `each'
    /usr/local/ruby_187/lib/ruby/gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:368:in `run_current_setup_blocks'
    /usr/local/ruby_187/lib/ruby/gems/1.8/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb:350:in `test: on DELETE to :destroy should delete the addresses phone numbers. '

2 tests, 1 assertions, 0 failures, 1 errors
rake aborted!
Command failed with status (1): [/usr/local/ruby_187/bin/ruby -I"lib:test" ...]

I think the key mystery is why it can't find the Address with that ID.

Another factor is that when I comment out this block, the remaining test passes.

    should 'delete the addresses phone numbers' do
      assert PhoneNumber.find(:all, :conditions => {
        :id => phone_numbers(:mary_publics_phone_number).id
      } ).blank?
    end

Anyone seen this before?

Troubleshooting suggestions?

+2  A: 

One thing to realize about Hashes in Ruby is that they don't retain ordering. I've had problems before that change the hash ordering depending on what code is loaded in memory -- even adding a puts "foo" somewhere would make a bug go away because I didn't realize the ordering of the Hash made a difference somewhere deep in the code. (Note: Hash does retain ordering in 1.9.1, specificly because of problems like that, if I were to guess.) This is consistent with what you say about how commenting out code makes other code pass. Since most fixtures are read in using YAML as Hashes, it's reasonable to think this might be a cause. Finding someplace that Hash ordering (i.e. in something like each) makes a difference may or may not make sense in your case. If nothing else, it's something to keep in mind.

Have you tried using Fixtures.identify(:mary_publics_phone_number) instead of phone_numbers(:mary_publics_phone_number).id? (See also: Fixtures documentation.) Another thing to keep in mind: you may not have unique fixture names. I'd check for duplicates, just in case. I know a lot of people who just copy and paste fixtures because they don't know about YAML's ability to give default values. In the process, they might forget to change the fixture's name. Example:

DEFAULTS: &DEFAULTS
  created_on: <%= 3.weeks.ago.to_s(:db) %>

first:
  name: Smurf
  <<: *DEFAULTS

Another issue I've had when moving from OS X to Linux is subtle differences in the Ruby version. (Even if both report 1.8.6, keep in mind that the patchlevel matters.) It used to be the case that the Red Hat version of Ruby had a memory leak in the garbage collector that required us to restart long running processes on occasion. (Before we realized what was going on, it created some hard to find bugs as they wouldn't happen for a long time.) Since CentOS is related to Red Hat (basically the same as RHEL), I could imagine other version differences causing issues. I know OS X never had the memory leak problem I described, which made it even harder to narrow the bug down. As far as differences go between 1.8.6 and 1.8.7, you'll have to refer to the change logs. Be aware that the version of Ruby built from source and the packaged version could behave differently -- I think the memory leak problem was introduced by whoever packaged Ruby.

Those are only a few possible causes. Please report back with what you find!

Benjamin Oakes
Thanks a lot for the help. It doesn't seem as though it could be a Hash ordering issue, but it's possible. Turns out there actually was a case of non-unique fixture names, but don't think it's related to this. We're going to try to install 1.8.6 on my coworker's system.
Ethan
Not a problem. I'm glad this has at least narrowed down the possible causes.Virtual machines might be useful for debugging this. If you aren't already committed to a product like VMware or Parallels, I'd recommend VirtualBox (http://www.virtualbox.org/). It's free, open source, and has both OS X and Linux versions. Never used it on CentOS, but I've had great experiences on OS X Leopard and Ubuntu.
Benjamin Oakes