Test Timing

Since Geoff's gem wasn't working for me, I whipped up a test timing utility based off of it.

Rather than hook into Test::Unit::TestSuite, I'm hooking into TestCase, and providing a global report via an at_exit hook. Just add the following file to your lib folder, require it from test_helper, and most of the time it will just sit there, quietly doing nothing. Call it into action by setting the environment variable TEST_TIMER with a float, and it will output the elapsed time of any test taking longer than that.

Example run:

# TEST_TIMER=0.25 rake test:units TEST=test/unit/creative_test.rb
/usr/bin/rake:17:Warning: require_gem is obsolete.  Use gem instead.
(in /home/jamie/dev/redvase)
/usr/bin/ruby1.8 -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/unit/creative_test.rb"
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader
Started
......................................................................................
Finished in 10.116575 seconds.

86 tests, 164 assertions, 0 failures, 0 errors

Test Benchmark Results
  0.2927 CreativeTest#test_delayed_click_count_with_third_party_stats
  0.2982 CreativeTest#test_impression_count_for_date_range_with_third_party_stats_offset
  0.3240 CreativeTest#test_global_creative_stats_should_return_correct_default_values
  6.2505 CreativeTest#test_click_count

Source file, lib/test_timer.rb

if ENV.has_key? 'TEST_TIMER' and
   !Test::Unit::TestCase.method_defined? :untimed_run

  class Test::Unit::TestCase
    cattr_reader :benchmark_data
    @@benchmark_data = {}
    alias untimed_run run

    def run(result, &progress_block)
      start = Time.now
      untimed_run(result, &progress_block)
      finish = Time.now
      elapsed = finish - start
      if elapsed > ENV['TEST_TIMER'].to_f
        name =~ /(.*)((.*))/
        @@benchmark_data["#{$2}##{$1}"] = elapsed
      end
    end
  end

  # at_exit hooks run in reverse order, so in order to run after
  # Test::Unit's hook, we need to nest at_exit calls.
  at_exit do
    at_exit do
      results = Test::Unit::TestCase.benchmark_data
      unless results.empty?
        puts "\nTest Benchmark Results"
        results.sort{|a,b| a.last <=> b.last }.each do |key,value|
          puts " %7.4f #{key}" % value
        end
      end
    end
  end
end

Reinstall

I'm running Ubuntu 6.10 on my laptop, and a few weeks back the sound decided that it would just stop working. I finally got fed up enough with it to do a reinstall. I thought I'd try out the new beta for Feisty, but the installer repeatedly froze on me at 63% on the install, so I gave up and put 6.10 back on. I try to keep tabs on what software I install as extras to ease reinstalls, and tweaked my reinstall scripts from last time to the final forms shown below.

After all this, I did manage to get sound up and running, and it even properly mixes now between Quod Libet, Gaim, and Firefox/flash. So, total win. Also I got to remove some cruft from my install, and I should be able to get up and running quick when I upgrade to 7.04. No in-place upgrade this time.

This first script takes a custom sources.list (just edited to enable universe/multiverse from all sources, and add a few extras for jedit and some others) and copies it into place, and then installs a new kernel, shell, network manager, and graphics driver. It sets up the networking for WPA (which I use at home). Lastly, it installs a special driver for my video hardware, with an init-script to let my LCD run at native resolution. Fun times I had figuring that one out.

#!/bin/sh

#sudo cp /etc/apt/sources.list /etc/apt/sources.list.old
#sudo cp sources.list /etc/apt/sources.list
#sudo apt-get update

# Environment
sudo apt-get install \
  build-essential zsh zsh-doc deborphan \
  linux-image-686 linux-restricted-modules-686 \
  nvidia-glx network-manager network-manager-gnome yakuake

# Get WPA networking set up
sudo echo auto lo > /etc/network/interfaces
sudo echo iface lo inet loopback >> /etc/network/interfaces
sudo echo ENABLED=0 > /etc/default/wpasupplicant
sudo /etc/init.d/dbus restart

# Fix screen res
cd 855resolution
make clean
make
sudo cp 855resolution /usr/sbin/855resolution
sudo cp 855res /etc/init.d/855res
sudo chmod 755 /etc/init.d/855res
sudo update-rc.d 855res defaults 19
cd ..

# Set shell
echo Enter your password to set zsh as your default shell
chsh -s /usr/bin/zsh

echo "\n\n\n\n\n\n"
echo Please reboot your system now to load the new kernel
echo and get X running at the correct resolution.
echo

After rebooting for a real X (and most of my working environment set up), I run the second script, which is essentially just one big batch-install. Version control, database, Java, Ruby, RubyGems (manually), a bunch of a/v codecs for gstreamer, and then a handful of actual applications.

#!/bin/sh

# Development
sudo apt-get install \
  subversion svk darcs mercurial \
  mysql-client mysql-server sqlite3 sqlite3-doc sun-java5-jre \
    sun-java5-plugin ia32-sun-java5-plugin sun-java5-fonts \
    ttf-sazanami-gothic ttf-sazanami-mincho \
  ruby1.8 ruby1.8-dev rdoc1.8 ri1.8 irb1.8 libyaml-ruby \
  libzlib-ruby libmysql-ruby librmagick-ruby libgd-ruby1.8

# Rubygems
wget http://rubyforge.org/frs/download.php/5207/rubygems-0.8.11.tgz
tar xzvf rubygems-0.8.11.tgz
cd rubygems-0.8.11
sudo ruby setup.rb
cd ..
rm -rf rubygems-0.8.11
rm rubygems-0.8.11.tgz
sudo gem update --system
sudo gem install rails camping nitro

# Multimedia/Entertainment
#  lame libdvdcss2
sudo apt-get install \
  alsa-oss vorbis-tools gstreamer0.10-ffmpeg \
  gstreamer0.10-plugins-bad gstreamer0.10-plugins-bad-multiverse \
  gstreamer0.10-plugins-ugly gstreamer0.10-plugins-ugly-multiverse \
  flashplayer-mozilla unrar unace p7zip \
  msttcorefonts gsfonts-x11 xfonts-intl-european
sudo fc-cache -f -v # reload font cache

# Apps
sudo apt-get install \
  quodlibet quodlibet-plugins quodlibet-ext \
  gnugo quarry wine jedit gnucash gnucash-docs

echo "\n\n\n\n\n\n"
echo Please edit /etc/firefox/firefoxrc and change \"none\" to \"aoss\"
echo

Comments

Wow, way more complicated than my installation process: http://dev.technomancy.us/phil/wiki/UbuntuInstallation

The most annoying part for me is grabbing all those firefox extensions since it's not easy to script. I've got fiesty herd 3 on my laptop, and it's working fine--better suspend than I got with edgy. But it's always hit-or-miss with these prereleases.

  • Phil Hagelberg, at 10:51, Feb 20 2007

Upgrading to 1.2, Part 1: Deprecations

So I've been spending some time lately working on upgrading the existing codebase for some projects at work such that they'll work in Rails 1.2 once it's released. Sadly, the upgrade process is not without its rough edges, and after two days of poking at it (it being a 5800 LOC app with 8800 LOC of tests) I'm still not completely done - the test run does not pass cleanly.

However, I have managed to get rid of most of the niggly deprecation warnings, so the output of the rake run is down to 450k from a high of about 2.2mb. Fun times. The changes required to silence most of the warnings are...

ActiveRecord

find_all and find_first are deprecated. Use find(:all) and find(:first) instead.

If you have a has_many which is :dependent, make sure you're specifying :destroy or :delete_all, rather than true. If you've got true you probably want to replace it with :destroy. Slower, but safer.

Routes

Just a short note here, :requirements regexps no longer accept anchors. We have something along these lines:

map.connect ':controller/:action/:foo', :requirements => { :foo => /^(bar|baz)$/ }

Such that that route only fires if the third url part is exactly bar or baz. To silence 1.2, just remove the ^ and $ anchors.

Controllers/Views

@params, @session, @request, and @flash are deprecated in controllers and views, use the version without the @. Note, don't try and change this globally in your tests, or all hell will break loose. Oddly, assigns(:flash) in a test seems to trigger the warning for accessing @flash.

If you want to have your link_to go by post instead of get, use :method => :post instead of :post => true.

(Update: This will not throw errors, but won't work in 1.1.6, so wait until you're actually running 1.2 to do this change.)

Rendering with a string (render 'template') is no longer allowed. The deprecation warning says to render :file => 'template' instead, but if you want your code to continue to work in Rails 1.1.6 you'll need to add a :use_full_path => true to the call.

start_form_tag and end_form_tag are now deprecated. The suggested replacement is to pass a block to a form_tag call, but that does not work at all in Rails 1.1.6. My preferred fix is to use a bare form_tag to start the form, and a hard-coded to finish it. Same goes with remote_form_tag for those AJAXy forms. That shuts up all the deprecation warnings, and allows for a fairly simple multiline regexp to blockify them up in the future. I was looking at something like <%= ?(remote_)?form_tag([^%]) ?%>(.?) and replacing with _<% $1form_tag$2 do %>$3<% end %>

We've got a few places where we're redirecting to a named route: redirect_to :login_url. This calls url_for, which is deprecated. I think the correct solution is to just drop the colon and redirect_to login_url, but this doesn't work in 1.1.6 and I haven't quite tested it yet.

Tests

Lastly, a change which I completely disagree with, assert_template_has and friends are now deprecated. Use assert(@response.has_session_object?(key)) instead, my ass. This changes removes a useful failure message like <:login> is not a template object and brings me back to the glory days of is not true. I know I'll be rewriting those as custom assertions for my test_helper, thank you very much.

To Be Continued

Like I said, I'm only half done this migration, but when I get the rest of it sorted, I'll be posting a follow-up right here. See you then.

Holding Pattern

Two quick notes for today.

First, come back Monday for a decent summary of the current state of the Rails 1.1 -> 1.2 upgrade situation. Summary: Pain.

Second, I'm conceding a temporary defeat to Mauricio. I'm getting somewhere, I just don't know where. If I have some time on Sunday I might poke at it a bit, but I'm mostly calling it quits for today.

How to crash Ruby

  class BrokenError < StandardError
    def backtrace
      raise(StandardError.new)
    end
  end

  begin
    raise BrokenError.new
  rescue e
    puts 'rescued'
  end

Because of the exception in the backtrace generation, processing just dies. If you have an at_exit block, it will still be run, so I suppose I'm not really crashing the ruby interpreter, I suppose, but it comes close.

Found this one out migrating a rails app from 1.1.6 to 1.2. Instead of doing this:

  render 'controller/action'

the deprecation warning suggests the following:

  render :file => 'controller/action'

Unfortunately, this causes the error if you're still trying to run in 1.1.6. A more complete fix is to make sure to add usefullpath to the render call to prevent an older TemplateError from horking, like so:

  render :file => 'controller/action', :use_full_path => true