Home / Blog / 2009 / July /

In a previous post I detailed changes I made to add Growl for Windows support to Autotest Growl.

These changes have now been integrated back into the autotest-growl gem. Along with some major improvements to the analysis of test results, and the details in the notifications. Thanks to Svoop, the creator of autotest-growl.

This gem isn’t yet available on Rubyforge, but you can grab a copy from my fork on GitHub until it is:

gem install karl-autotest-growl --source http://gems.github.com

This should be a drop in replacement for the previous version of karl-autotest-growl, the only thing you should notice more detail from the growl notifications!

I’ll post again once the official gem is available on Rubyforge.

I previously posted an update that enables Growl notifications for Autotest in Windows.

Which is nice, but what about other Ruby programs, they might want to send Growl notifications too. To this end Vision Media have produced a Ruby Growl gem which makes it easy for any Ruby program to send Growl notifications.

But the visionmedia-growl gem only works on OSX.

Now With Added Windows Support

So I had a go at adding Windows support. The short version is that it works, but the code is seriously ugly and not well tested (you have been warned!).

Check out my visionmedia-growl fork. Or just install the gem:

sudo gem install karl-growl --source http://gems.github.com

Packaging growlnotify

First up I decided to package both the OSX and Windows versions of growlnotify with the gem.

This is a departure from the existing gem, which requires that you have installed growlnotify yourself. I wanted to be able to include this gem in new projects without having to bother users to download extra dependencies.

Choose the Right growlnotify

I decide which growlnotify to use by checking which platform we are running on:

51
52
53
54
55
56
57
58
59
60
61
62
63
64
  def self.is_windows?
    processor, platform, *rest = RUBY_PLATFORM.split("-")
    platform == 'mswin32'
  end
 
  ##
  # Execute +args+ against the binary.
 
  def self.exec *args
    bin = PACKAGED_BIN
    bin += '.com' if is_windows?
 
    Kernel.system bin, *args
  end

Different Switches on Different Operating Systems

The biggest headache with adding Windows support was adding the ability to generate Windows style command line arguments.

Example OSX command line:

growlnotify --message llamas --title Llama! --image images/llama.png

Example Windows command line:

growlnotify.com llamas /t:Llama! /i:images/llama.png

Note that in the Windows command line, switches are specified with /x: prefix, and no space. The names of the switches don’t correspont exactly with the OSX ones.

Also, with the Windows version of growlnotify you don’t give an switch for the message body, just include it as the first argument.

Adding Support for Windows Style Switches

The first part of adding this support was to map the OSX switches to their Windows counterparts (where they existed).

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
    switch :title,      :t
    switch :sticky,     :s
    switch :priority,   :p
    switch :host,       :host
    switch :password,   :pass
    switch :port,       :port
 
    switch :name,       :a
    switch :message,    :EMPTY
    switch :image,      :i
    switch :identifier, :id
 
    switch :iconpath,   nil
    switch :appIcon,    nil
    switch :icon,       nil
 
    switch :udp,        nil
    switch :auth,       :hash
    switch :crypt,      nil

As you can see, not all OSX switches are available in the Windows version of growlnotify. I dealt with this at the moment, by just stripping out any switches that won’t work in Windows.

Finally I altered (hacked?) the Growl run method, to produce parameter strings for either OSX or Windows.

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    def run
      raise Error, 'message required' unless message
      self.class.switches.each do |name, win_name|
        if send(:"#{name}?")
          value = send(name).to_s if send(name) && !(TrueClass === send(name))
          if is_windows?
            next if win_name.nil?
 
            switch = (win_name == :EMPTY) ? "" : "/#{win_name}:"
            args << switch + value
          else
            args << "--#{name}"
            args << value
          end
        end
      end
      Growl.exec *args
    end

The main points of interest here are the The windows switches don’t have any space between the switch name and the value. So instead they are concatenated together into a single string.

Finally we deal with the special case where using the Windows version of growlnotify we need to add the message parameter without a switch, so we use the special token :EMPTY to deal with this.

The Result

The results of this is a Ruby gem that supports Growl notifications in Windows. The gem can be installed with the following commands:

sudo gem install karl-growl --source http://gems.github.com

And used in your Ruby program as follows:

Growl.notify {
    self.message = 'Hello World'
    self.image = File.join 'path', 'to', 'image.png'
  }

For more usage examples see the karl-growl site.

Known Issues

There are a few known issues. The biggest of which no support for normalised icons.

To support OSX and Windows always give a path to an image, e.g.

  :image => 'path/to/image.png'

There are a number of switches that only work in OSX, and are ignored in Windows. Unsupported switches are:

  :iconpath
  :appIcon
  :icon
  :udp
  :crypt

The gem has only received the most cursory of testing, so there may be a whole host of other issues, be warned!

The Future

I’m treating the current version of this gem, as a design spike, a proof of concept that shows we can have cross Operating System support. The code is a real mess, and has no unit tests, but I’m releasing it here to follow the ‘better now beats best later’ rule.

I hope to refactor the code into something more production worthy when I get a chance.

Autotest Growl for Windows

July 10th, 2009

In a previous blog post I detailed how to get Autotest Growl notifications on Windows using Snarl. But, there now exists an official Growl client for Windows.

So how about we update autotest-growl to support Windows (on top of it’s existing support for OSX).

If you don’t want to know all the gory details, you can just install my fork of the autotest-growl gem, that includes native Growl Windows support:

gem install karl-autotest-growl --source http://gems.github.com

Obviously, you’ll need to have Growl for Windows installed as well!

Updating Autotest Growl to support Windows

First up download and install Growl for Windows (if you haven’t already).

Updating Autotest Growl turns out to be pretty simple. We need to download growlnotify for Windows, and add it to the growl/ directory.

Then we can update the autotest-growl code to decide which growlnotify to use depending on the Operating System.

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  def self.is_windows?
    processor, platform, *rest = RUBY_PLATFORM.split("-")
    platform == 'mswin32'
  end
 
  ##
  # Display a message through Growl.
  def self.growl title, message, icon, priority=0, stick=""
    growl = File.join(GEM_PATH, 'growl', 'growlnotify')
    image = File.join(ENV['HOME'], '.autotest-growl', "#{icon}.png")
    image = File.join(GEM_PATH, 'img', "#{icon}.png") unless File.exists?(image)
 
    if is_windows?
      growl += '.com'
      cmd = "#{growl} #{message.inspect} /a:\"autotest\" /r:\"Autotest\" /n:\"Autotest\" /i:\"#{image}\" /p:#{priority} /t:\"#{title}\""
    else 
      if @@remote_notification
        cmd = "#{growl} -H localhost -n autotest --image '#{image}' -p #{priority} -m #{message.inspect} '#{title}' #{stick}"
      else
        cmd = "#{growl} -n autotest --image '#{image}' -p #{priority} -m #{message.inspect} '#{title}' #{stick}"
      end
    end
 
  system cmd
  end

You’ll notice that the command line flags are slightly different for the Windows version of growlnotify, the using the /x: format, rather than the OSX -x format.

The Windows version also adds the flat /r:"Autotest" to ensure the Autotest application is registered the first time it is run.

There is no need to deal with the @@remote_notification settings, as Growl for Windows does not have the same problem with intermittent notification loss that OSX does.

Installing updated Autotest Growl gem

I have rolled all these changes into my fork of autotest-growl. To switch over to this fork, open a Windows command prompt and enter:

gem uninstall autotest-growl
gem install karl-autotest-growl --source http://gems.github.com

And then watch the notifications roll in!

Update to QUnit Adapter

July 2nd, 2009

I’ve made a small update to the QUnit Adapter for JS Test Driver.

This fixes a bug where the ok() assertion was much stricter than the qunit equivalent. It was only succeeding when passed a boolean true value.

Now it behaves the same as the qunit version, and succeeds with all values other than 0, false, or null.

You can get the new 1.0.1 verison of the QUnit Adapter from Google Code.

As part of my experimenting with JS Test Driver, I have been porting over a suite of about 300 existing tests.

Some of these tests deal with time based logic, such as delayed callbacks or time limited user interaction. Currently these tests are run in a HTML page using qunit.

To deal with the time based logic I use the jsUnit’s Mock Timeout. See Simulating Time in jsUnit Tests on the Google Testing Blog.

jsUnit’s Mock Timeout overrides the built in setTimeout, clearTimeout, setInterval, and clearInterval methods, and provides a Clock object that allows you to control the passage of time.

Problem

This works fine in qunit, but it fails catastrophically in JS Test Driver. This is because JS Test Driver uses the setTimeout and setInterval methods to control it’s own behaviour. Once these have been overridden with the mock versions JS Test Driver no longer works.

As a temporary fix for this I have created a patched version of JS Test Driver, which creates it’s own copies of the original setTimeout, clearTimeout, setInterval, and clearInterval methods, before loading any code. This ensures it works well with the jsUnit Mock Timeout.

Patched JS Test Driver

Download a patched JsTestDriver with no-confilict timeouts.

Just use this jar in place of the original JsTestDriver-1.0b.jar, and you can include jsUnitMockTimeout.js in your tests without breaking JS Test Driver!

You may also want to download jsUnitMockTimeout.js (to save you finding it within the jsUnit source).

The Future

I see this patched JS Test Driver as very much a temporary stepping stone, while the correct solution is worked out. Beware of relying on it too heavily!

**Update**: [This solution has been integrated into JS Test Driver](http://groups.google.com/group/js-test-driver/browse_thread/thread/1393946af440ed90/c532267cd6c90710#c532267cd6c90710), and will be available in the next release.

In my last post I introduced a QUnit to JS Test Driver adapter, a small adapter which converts QUnit tests into native JS Test Driver tests.

This adapter is now part of the JS Test Driver project.

There is now a QUnit Adapter wiki page on the JS Test Driver project site. This will be updated to keep up with any changes to the adapter.

The code is now stored within the JS Test Driver subversion repository. You can always download the latest version of the QUnit Adapter using the Google Code web interface.

Thanks to Jeremie Lenfant-engelmann for deeming QUnit Adapter worthy of official regonition :)