Where I work, we’ve been starting to use Ruby for some of our glue code as a replacement for bash scripts, and Ruby/Rake for our build infrastructure as a replacement for Make and Ant. One of the main reasons for this transition is to make it easier to test these parts of our system. For the most part this has worked well, but there are still a few places where I’m trying to figure out the best way to write the tests.

Here’s an example of part of a build script I wrote a few months ago. I used TDD and have the script working, but I’m not completely happy with how it turned out.

The script takes a pre-populated directory and builds a Debian package out of it, uploads it to a server that hosts our local Debian repository, and includes the new package in the repository.

To build the package, we use the command:

fakeroot dpkg-deb -b #{source_directory} #{target_directory}

The name of the package that is built is printed on stdout in the following format:

dpkg-deb: building package my-package in /path/to/my-package_123_i386.deb

The name of the .deb file is determined by information contained in the Debian control file. Rather than duplicating the logic that dpkg-deb uses to generate the filename, the script parses this output to determine the filename. This is the file to upload to the server.

We use scp to upload the file to the repository host.

To include the package in the repository after uploading, we ssh into the repository host and invoke the command:

reprepro -Vb /debian-local includedeb squeeze #{filename}

There are a couple of special requirements:

  • If the pre-populated directory contains a special known path, we need to run a chown command in the same fakeroot session as the dpkg-deb command above. So, the command would become:

fakeroot bash -c "chown -R 1000.1000 #{special_directory} && dpkg-deb -b #{source_directory} #{target_directory}"

  • If the script is running on the repository host machine, there is no need to upload the file first; we can just run the reprepro command directly.

How would you tackle this problem in Ruby using TDD?

I realize that there may be better ways to do some of this, but it integrates with existing infrastructure that would take more time to change than I’m willing to invest at the moment. In this post, I’m only asking for advice on how you’d build this tool using TDD in Ruby.

As I mentioned, I’ve already built this so I’m not asking you to “do my homework” for me. I just want to see some other ways to tackle this problem and to improve my technique in the area of testing Ruby programs that are essentially shell script replacements.

If you’re interested in participating, you can comment below, send me your ideas and/or solution by e-mail (see the bottom of my About Page), send, post, or tweet a link to a Gist or GitHub repo, or any other means of ensuring that I see your response. I’d love to see some code, but even a brief description of your approach would be welcome.

If you have any questions, or if anything is unclear, please get in touch with me. If needed, I’ll post some additional clarifications as needed.

I’ll post my implementation and tests here in a few weeks, and I’ll also summarize the responses I get.