Fail Loudly with osd_cat and autotest

A key to Test Driven Development is frequently run tests. These tests are used to judge the health of a project. Like in a hospital, when things deteriorate we have to be alerted right away.

Ruby developers use autotest to monitor and run their test suite in the background. One problem with autotest is that the results are printed to the console. No alert, no notification, no loud failure. OSX users are able to hook autotest up to growl, allowing growl to flash test results above all the windows.

Unfortunately, growl is only available for OSX, I need a Linux solution. I found someone using Knotify with autotest but the result window was tiny and easy to miss. I needed something bigger and more noticeable.

I remembered a friend used a program called osd_cat to build a volume control UI for his Linux DVR. osd_cat (On Screen Display cat) is a command line program that will print text above all your windows, similar to growl. Unlike Knotify, osd_cat can print text large and bright red.

In order to use osd_cat we need to install the program, called xosd-bin in Debian, and then hook it up to Autotest. When autotest starts it will read a Ruby file called .autotest. Using that file, I was able to hook up autotest to osd_cat. My current autotest file is adapted from several sources online and works with both RSpecs and Test::Unit.

Now I got a loud and alarming message whenever my tests fails. Not a puny little alert window but a big honking in your face "Something broke!" message:

Failed autotest

Fixed autotest

.autotest file:

!/usr/bin/ruby

NOTE Copy this to your home folder as .autotest

#

Originally from http://wincent.com/knowledge-base/Setting_up_autotest_to_use_Growl

#

Modifications:

* Changed from Growl to osd_cat on Linux

[Eric Davis http://theadmin.org]

* Minor refactoring to use .autotest_images directory

[Geoffrey Grosenbach http://peepcode.com]

* Test::Unit compatibility [Pat Nakajima]

require 'autotest/timestamp' # time plugin

module Autotest::OsdCat # Use xlsfonts to find the different fonts FONT="-bitstream-charter-bold-r-normal--33-240-100-100-p-206-iso8859-1"

# Will display the message on the top of the screen centered, adjust these numbers to suit. POSITION="top" # top|middle|bottom POSITION_OFFSET="0" # Pixels from position to display (think CSS margin) ALIGN="center" # left|right|center

def self.osd_cat msg, color='green'

osd_command = "echo #{msg.inspect} | osd_cat --font=#{FONT} --shadow=0 --pos=#{POSITION} -o #{POSITION_OFFSET} --delay=2 --outline=4 --align=#{ALIGN} -c #{color}"

# osd_cat blocks so start a new thread, otherwise Autotest will wait
t1 = Thread.new do
  `#{osd_command}`  
end

end

def self.osd_cat_fail(output)

osd_cat "#{output}", 'red'

end

def self.osd_cat_pass(output)

osd_cat "#{output}"

end

Autotest.add_hook :ran_command do |at|

results = [at.results].flatten.join("\n")

if results.include? 'tests'
  output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?(,\s*(\d+)\s+errors)?/)
  if output
    $~[3].to_i + $~[5].to_i > 0 ? osd_cat_fail(output) : osd_cat_pass(output)
  end
else
  output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+not implemented)?/)
  if output
    $~[2].to_i > 0 ? osd_cat_fail(output) : osd_cat_pass(output)
  end
end

end

end

From: http://www.ridaalbarazi.com/blog/2007/04/05/autotest-growling-in-red-green/

class Autotest # All code borrowed from: # http://www.robsanheim.com/2006/08/07/hacking-green-bar-color-output-into-autotest/

BAR = "=" * 80

# filter output for colorized green/red bar def filter_output(results)

filtered = ""
results.each do |line|

  if line =~ /\d+ tests, \d+ assertions, 0 failures, 0 errors/
    line = "\e[32m#{BAR}\n#{$&}\e[0m\n\n"
  elsif line =~ /\d+ tests, \d+ assertions, (\d+) failures, (\d+) errors/
    if $1 != 0 || $2 != 0
      line =  "\e[31m#{BAR}\n#{$&}\e[0m\n\n"
    end
  end
  filtered << line
end
filtered

end

def run_tests

find_files_to_test # failed + changed/affected
cmd = make_test_cmd @files_to_test

puts cmd

@results = `#{cmd}`
hook :ran_command
puts filter_output(@results)

handle_results(@results)

end end

Eric

Tagged: autotest development ruby ruby on rails testing