26 May 2017

Vlad Mihalcea recently posted the blog How to run integration tests at warp speed using Docker and tmpfs, and I thought it would be interesting to see what needed to be done to run the Jaybird tests against a Firebird instance on docker.

I am writing this post as documentation for myself, but I hope it might be useful for others as well. Note that I don’t have a lot of experience with docker, so do not assume that things in this blog are docker best practices.

As a baseline, a normal test run from IntelliJ on my local machine takes about 10 - 11 minutes for Jaybird master (Jaybird 3.1).

Initial setup

For this experiment, I used the jacobalberty/firebird image.

The Jaybird tests include tests for events, and the documentation of the image suggests that to use events, you need to add --net=host to the docker run command, or RemoteAuxPort must be set and mapped. I use Docker for Windows, and unfortunately --net=host is not supported on Windows.

I started the image with:

docker run `
 --name firebird257 `
 -p 3050:3050 `
 -p 13050:13050 `
 --tmpfs /databases:rw `
 -e ISC_PASSWORD=masterkey `
 -e TZ=Europe/Amsterdam `
 -d `
 jacobalberty/firebird:2.5.7-ss

I’m using powershell, which uses ` as the line continuation character, for Windows cmd use ^, for Linux (bash) use \.

Note the use of --tmpfs /databases:rw to ensure the databases folder is using tmpfs, which is in-memory.

To get events to work I edited the /var/firebird/etc/firebird.conf (which, btw, is not a best practice!) to set RemoteAuxPort=13050, and stopped and started the image with docker stop firebird257 and docker start firebird257. A better solution would be to overlay the config file, but my docker-fu is lacking in this area for the moment.

As I’m binding port 3050 directly in this example, I need to make sure that no other instance of Firebird is running on that port locally.

First attempt

As my configuration above binds the image to 127.0.0.1:3050, I had assumed I could just run all tests from my IDE and be done with it, unfortunately this failed with:

SEVERE: Exception creating database
java.sql.SQLException: unavailable database [SQLState:08001, ISC error code:335544375]
	at org.firebirdsql.gds.ng.FbExceptionBuilder$Type$1.createSQLException(FbExceptionBuilder.java:498)
	at org.firebirdsql.gds.ng.FbExceptionBuilder.toFlatSQLException(FbExceptionBuilder.java:299)
	...

Oops. When Jaybird is run against a database on 127.0.0.1 or localhost, the test harness will try to put the database in the current working directory by transforming the relative path to an absolute path. And this obviously fails when you try to pass that absolute Windows path to a Linux image.

Fortunately, all 127.x.x.x addresses point to the local loopback, so running the tests against 127.0.0.2 should work just fine.

Second attempt

Adding -Dtest.db.host=127.0.0.2 to the run configuration of the tests should do the trick.

And it seems to work, although a number of tests fail. These failures can be explained though, as these tests expect the database or backup file to exist on the local filesystem, which now is not the case (just like when testing against a real remote database server). We’ll ignore these failures for now.

Unfortunately, the runtime of the test is 9+ minutes, and that is not significantly different from the original results. Inspection of the image using docker exec -i -t firebird257 /bin/bash and checking the /databases folder shows that the databases aren’t created in the /databases folder. It turns out they are being created in /tmp instead. This is probably caused by Jaybird using /fbtest.fdb as the database name instead of just fbtest.fdb, or maybe that is a result of the configuration in the image, I’m not sure. Explicitly specifying the /databases path should do the trick.

Third attempt

This time we also add -Dtest.db.dir=/databases to the run configuration.

And finally, we hit pay dirt: a run time of 3 minutes and 30 seconds. A reduction of about 7 minutes.

Up to now I have run the tests from my IDE, to run the ant build this way:

build -Dtest.db.host=127.0.0.2 -Dtest.db.dir=/databases

The performance improvement from running the tests from ant seems to be the same in absolute terms (from 12 minutes to 6-7 minutes without the build itself).

Conclusion

The results are certainly interesting. I will now need to find a cleaner way to change the configuration, and also run the tests against Firebird 3 (which requires additional configuration changes to work with Jaybird). To be continued.