169 lines
5.7 KiB
Markdown
169 lines
5.7 KiB
Markdown
+++
|
|
date = "2016-04-15"
|
|
title = "Hanami and Multi-Database Testing with Travis"
|
|
tags = ["hanami", "travis", "testing"]
|
|
description = "Hanami: good! Travis: good! Testing your code against multiple databases: priceless!"
|
|
slug = "hanami-and-multi-database-testing-with-travis"
|
|
+++
|
|
|
|
_This is a re-post of my article over at [Kabisa](https://kabisa.nl)'s [The Guild](https://www.theguild.nl/hanami-and-multi-database-testing-with-travis)._
|
|
|
|
I've been busy rewriting [Firefly](https://github.com/ariejan/firefly) for a while now using
|
|
[Hanami](http://hanamirb.org). Hanami is a fascinatingly fresh ruby web framework with a
|
|
strong opinion on _Clean Architecture_. Me like!
|
|
|
|
## Why test against different databases
|
|
|
|
Initially I developed Firefly to use Sqlite for database storage. However, Sqlite
|
|
is not always the _best_ option. Running Firefly on [Heroku](https://heroku.com) for
|
|
instance would be impractical, since Heroku's architecture assumes you use a _real_
|
|
database, like Postgres.
|
|
|
|
Firefly being open source also means that different users will want to use a
|
|
database that they're already familiar with, or one that's already running for
|
|
other apps.
|
|
|
|
## Supporting multiple databases
|
|
|
|
The _big three_ relational databases I want to support are Sqlite, MySQL and PostgreSQL.
|
|
Hanami uses [Sequel](http://sequel.jeremyevans.net/). This means my code is already
|
|
abstracted from specific database implementation. As long as Sequel supports it, so
|
|
can Firefly.
|
|
|
|
The only problem I encountered was the fact that MySQL `datetime` fields do not store
|
|
fractions of seconds, which messed with some tests. This was easily taken care of.
|
|
|
|
## Travis
|
|
|
|
[Travis](https://travis-ci.org) is an awesome CI-as-a-Service provider. Open
|
|
source projects can even use their service for free! <3
|
|
|
|
Whenever a new commit is made (on `master` or in Pull Requests), Travis will
|
|
check out the code, do some setup specified in a `.travis.yml` file and report
|
|
back the test status.
|
|
|
|
The thing is that, with multiple databases, we need to tell Travis to run
|
|
multiple sub-builds for each database. We also need to tell Travis how
|
|
to configure / setup Firefly to use each database properly.
|
|
|
|
## Hanami and databases
|
|
|
|
Before setting up multiple databases, let's check how Hanami configures a
|
|
database connection.
|
|
|
|
# lib/firefly.rb
|
|
Hanami::Model.configure do
|
|
# * SQL adapter
|
|
# adapter type: :sql, uri: 'sqlite://db/firefly_development.sqlite3'
|
|
# adapter type: :sql, uri: 'postgres://localhost/firefly_development'
|
|
# adapter type: :sql, uri: 'mysql://localhost/firefly_development'
|
|
#
|
|
adapter type: :sql, uri: ENV['FIREFLY_DATABASE_URL']
|
|
|
|
So, the actual database URI is set using an environment variable. Hanami
|
|
makes use of the `dotenv` gem, which will load a `.env` or `.env.test` file
|
|
depending on which environment Hanami runs in. Somehow we'd need different
|
|
`.env.test` files for each database configuration
|
|
|
|
For Sqlite:
|
|
|
|
# .env.test.sqlite
|
|
FIREFLY_DATABASE_URL="sqlite://db/firefly_development.sqlite3"
|
|
|
|
For MySQL:
|
|
|
|
# .env.test.mysql
|
|
FIREFLY_DATABASE_URL="mysql://root@localhost/firefly_test"
|
|
|
|
For Postgres:
|
|
|
|
# .env.test.postgresql
|
|
FIREFLY_DATABASE_URL="postgres://localhost/firefly_test"
|
|
|
|
There's also the issue of dependencies. For instance, when using PostgreSQL,
|
|
the `pg` gem should be included in `Gemfile`. If you're running with Sqlite,
|
|
you do _not_ want that dependency there. Here I'd like to take the same
|
|
approach and create multiple Gemfiles that each specify their own
|
|
dependencies as needed.
|
|
|
|
For Sqlite:
|
|
|
|
# gemfiles/Gemfile.sqlite
|
|
gem 'sqlite3'
|
|
|
|
For MySQL:
|
|
|
|
# gemfiles/Gemfile.mysql
|
|
gem 'mysql'
|
|
|
|
For Postgres:
|
|
|
|
# gemfiles/Gemfile.postgresql
|
|
gem 'pg'
|
|
|
|
## Tying it all together
|
|
|
|
What's left to is tell Travis about the different database and put the right
|
|
files in place at the right time.
|
|
|
|
First, I setup the environment variables for each database. This triggers Travis
|
|
to run a build for each combination of variables:
|
|
|
|
# .travis.yml
|
|
env:
|
|
- DB=sqlite
|
|
- DB=mysql
|
|
- DB=postgresql
|
|
|
|
Travis will run the build three times, each time with a different `DB` value set.
|
|
|
|
The process of the Firefly build is like this:
|
|
|
|
# .travis.yml
|
|
install: bundle install --jobs=3 --retry=3 --without production
|
|
|
|
script:
|
|
- 'HANAMI_ENV=test bundle exec hanami db create'
|
|
- 'HANAMI_ENV=test bundle exec hanami db migrate'
|
|
- 'bundle exec rake test'
|
|
|
|
What I want is hook into different places and setup the right `.env` and `Gemfile`
|
|
for the specified database. As it turns out Travis provides `before_install` and
|
|
`before_script` hooks. By making use of the specified `DB` environment variable,
|
|
it really is just a matter of copying the right files into place.
|
|
|
|
# .travis.yml
|
|
before_install:
|
|
- cp gemfiles/Gemfile.$DB Gemfile
|
|
|
|
install: bundle install --jobs=3 --retry=3 --without production
|
|
|
|
before_script:
|
|
- cp .env.test.$DB .env.test
|
|
|
|
script:
|
|
- 'HANAMI_ENV=test bundle exec hanami db create'
|
|
- 'HANAMI_ENV=test bundle exec hanami db migrate'
|
|
- 'bundle exec rake test'
|
|
|
|
That's all it takes to run your tests against multiple databases with Hanami!
|
|
|
|
## Bonus: test against multiple rubies
|
|
|
|
Testing against multiple databases is cool, but it's also very well possible
|
|
that end-users will not be using the greatest and latest ruby version. Firefly
|
|
currently support the latest 2.2.x and 2.3. versions of Ruby. Travis supports
|
|
this out of the box:
|
|
|
|
# .travis.yml
|
|
rvm:
|
|
- 2.2.4
|
|
- 2.3.0
|
|
|
|
This, in combination with our database setup, will trigger six builds. Sqlite,
|
|
MySQL and PostgreSQL builds on ruby-2.2.4 _and_ on ruby-2.3.0.
|
|
|
|
![Travis builds](/img/travis-firefly-builds.png)
|
|
|
|
I hope you liked this post. Happy coding and keep testing!
|