Using Mozmill to Test Firefox Extensions

Recently I’ve been working on a Firefox extension, and needed a way to test the code.  While testing code is always important, it is particularly important for dynamic languages where code that hasn’t been run is more likely to be buggy.

I had not experience in how to do this for Firefox extensions, so Eric suggested I try out Mozmill. which has been quite helpful so far.  There were no Ubuntu packages for it, so I’ve put some together in my PPA for anyone interested:

The packages are not quite up to the standard needed to go into Ubuntu yet (among other things, there are no man pages for the various commands), but they do work and shouldn’t eat your system.

Running mozmill tests is pretty easy, and can be done with a command like the following:

mozmill --addons=$PATH_TO_YOUR_EXTENSION \
    --show-errors --test=$PATH_TO_YOUR_TESTS

This will launch an instance of Firefox using a temporary scratch profile that loads your extension, and then run your tests.  The tests will run inside the Firefox instance with the results fed back to the mozmill utility.  When the tests complete, the Firefox instance will exit and the scratch profile deleted.

While many of the mozmill tests that Mozilla has written are relatively high level, essentially treating it as an user input automation system, you have full access to Mozilla’s component architecture, so the framework seems well suited to lower level unit testing and functional tests.

Tests are structured as simple javascript modules, and uses conventions similar (although not identical) to many other xUnit frameworks.  Any function whose name starts with “test” is a test.  If the module contains “setupTest” or “teardownTest” functions, they will be called before and after each test respectively.  If the module contains “setupModule” or “teardownModule” functions, they will be called before and after all the tests in the module run, respectively.

There is a “jumlib” module that you can import into your tests that provides familiar helpers like assertEquals(), etc.  One difference in their behaviour to what I am used to is that they don’t interrupt the test on failure.  On the plus side, if you’ve got a bunch of unrelated assertions at the end of your test, you will see all the failures rather than just the first.  On the down side, you don’t get a stack trace with the failure so it can be difficult to tell which assertion failed unless you’ve provided a comment to go with each assertion.

The framework seems to do the job pretty well, although the output is a little cluttered.  It has the facility to publish its test results to a special dashboard web application, but I’d prefer something easier to manage on the command line.

linux.conf.au 2011

I’ve just got through the first one and a half days of LCA2011 in Brisbane. The organisers have done a great job, especially considering the flooding they have had to deal with.

Due to the venue change the accommodation I booked is no longer within walking distance of the conference, but the public transport is pretty good.  A bit more concerning was the following change to the wiki made between the time I left Perth and the time I checked in:

BYO Toilet Paper

I’ve been impressed with the conference talks I’ve been to so far. In particular, I liked Silvia Pfeiffer’s talk on audio/video processing with HTML5 – I’ll have to have a play with some of this. Today’s keynote was by Vint Cerf about the history of internet protocols and what the challenges will be in the future (e.g. InterPlaNet).

There was a talk today about Redis: it sounded like interesting technology, but the talk didn’t really give enough information to say when you’d choose it over other systems.

Bagels

I made some bagels last night.  It was my second time using the recipe, so things went pretty well.  The boiling process gives the crust an interesting chewy texture I haven’t seen with other bread recipes I’ve tried.

I used this recipe (half wholemeal flour, half white), but made 12 slightly larger bagels rather than the 18 the recipe suggested.  I increased the boiling and baking time a bit to compensate.  They weren’t particularly difficult to make, but the boiling process was fairly time consuming, since I could only fit three at a time into the pot.

Bagels

Launchpad code scanned by Ohloh

Today Ohloh finished importing the Launchpad source code and produced the first source code analysis report.  There seems to be something fishy about the reported line counts (e.g. -3,291 lines of SQL), but the commit counts and contributor list look about right.  If you’re interested in what sort of effort goes into producing an application like Launchpad, then it is worth a look.

Seeking in Transcoded Streams with Rygel

When looking at various UPnP media servers, one of the features I wanted was the ability to play back my music collection through my PlayStation 3.  The complicating factor is that most of my collection is encoded in Vorbis format, which is not yet supported by the PS3 (at this point, it doesn’t seem likely that it ever will).

Both MediaTomb and Rygel could handle this to an extent, transcoding the audio to raw LPCM data to send over the network.  This doesn’t require much CPU power on the server side, and only requires 1.4 Mbit/s of bandwidth, which is manageable on most home networks.  Unfortunately the only playback controls enabled in this mode are play and stop: if you want to pause, fast forward or rewind then you’re out of luck.

Given that Rygel has a fairly simple code base, I thought I’d have a go at fixing this.  The first solution I tried was the one I’ve mentioned a few times before: with uncompressed PCM data file offsets can be easily converted to sample numbers, so if the source format allows time based seeking, we can easily satisfy byte range requests.

I got a basic implementation of this working, but it was a little bit jumpy and not as stable as I’d like.  Before fully debugging it, I started looking at the mysterious DLNA options I’d copied over to get things working.  One of those was the “DLNA operation”, which was set to “range” mode.  Looking at the GUPnP header files, I noticed there was another value named “timeseek”.  When I picked this option, the HTTP requests from the PS3 changed:

GET /... HTTP/1.1
Host: ...
User-Agent: PLAYSTATION 3
Connection: Keep-Alive
Accept-Encoding: identity
TimeSeekRange.dlna.org: npt=0.00-
transferMode.dlna.org: Streaming

The pause, rewind and fast forward controls were now active, although only the pause control actually worked properly. After fast forwarding or rewinding, the PS3 would issue another HTTP request with the TimeSeekRange.dlna.org header specifying the new offset, but the playback position would reset to the start of the track when the operation completed. After a little more experimentation, I found that the playback position didn’t reset if I included TimeSeekRange.dlna.org in the response headers. Of course, I was still sending back the beginning of the track at this point but the PS3 acted as though it was playing from the new point in the song.

It wasn’t much more work to update the GStreamer calls to seek to the requested offset before playback and things worked pretty much as well as for non-transcoded files.  And since this solution didn’t involve byte offsets, it also worked for Rygel’s other transcoders.  It even worked to an extent with video files, but the delay before playback was a bit too high to make it usable — fixing that would probably require caching the GStreamer pipeline between HTTP requests.

Thoughts on DLNA

While it can be fun to reverse engineer things like this, it was a bit annoying to only be able to find out about the feature by reading header files written by people with access to the specification.  I can understand having interoperability and certification requirements to use the DLNA logo, but that does not require that the specifications be private.

As well as keeping the specification private, it feels like some aspects have been intentionally obfuscated, using bit fields represented in both binary and hexadecimal string representations inside the resource’s protocol info.  This might seem reasonable if it was designed for easy parsing, but you need to go through two levels of XML processing (the SOAP envelope and then the DIDL payload) to get to these flags.  Furthermore, the attributes inherited from the UPnP MediaServer specifications are all human readable so it doesn’t seem like an arbitrary choice.

On the bright side, I suppose we’re lucky they didn’t use cryptographic signatures to lock things down like Apple has with some of their protocols and file formats.