Testing Multiple Rubies and Databases on Travis CI21 Mar 2013
Why should I test multiple versions & databases
In the Ruby community, it’s expected that your open source projects should have automated testing. It gives other developers who use your code confidence that your code works as expected and rather than crashing their production app (as fun as that is to deal with). With the additional of free remote automated testing, testing and publishing results is dead simple.
This has been a huge leap forward for the open source community.
I think the next leap forward is to intentionally test against language versions and infrastructure components (databases) outside the scope of your initial project. Why? If I create and test a Ruby gem against MySQL but you want to use it with Postgresql, how do know the code is a solid solution for your Postgresql infrastructure? You don’t unless you dig through my the code.
But, the purpose of being a developer is NOT coding or programming. Being a developer is about choosing how and when to leverage code & systems (for more on this view point, see True Nature of Code).
Let’s setup testing within a Rails app and configure these 9 different setps. https://travis-ci.org/westonplatter/example_travisci_multi
Rspec testing a Rails project
I use Rspec for testing Rails applications, but your actual testing framework could be anything. Thus, starting with a new rails project, let’s install the rspec-rails gem into our rails project.
# create the rails app rails new example_travisci_multi cd example_travisci_multi # add rspec-rails to Gemfile echo 'gem "rspec-rails"' >> Gemfile bundle install rails generate rspec:install # create rails testable resource rails generate scaffold Post title:string # run rspec rake db:migrate rake db:test:preapre rake spec
How do we know which Ruby version and which database we are using?
rake about # About your application's environment # Ruby version 1.9.3 (x86_64-darwin12.2.1) # ... # Database adapter sqlite3 # ...
Let’s get Ruby 1.9.3 and Sqlite3 working with Travis CI before we expand to other Rubies and Databases.
Travis CI for Github public repo
Having created a Rails project, configured your test framework, and confirmed your tests run, let’s configure it with Travis CI (free for open source projects). We’ll assume your code is hosted on Github as a public project.
- Go to the Github project admin panel, click on serivce hooks section, (EG, https://github.com/GITHUB_USERNAME/REPO_NAME/settings/hooks).
- If you haven’t setup a travis ci account, do so. Go to [https://travis-ci.org](https://travis-ci.org/), and click on “Sign in with Github”.
- Copy and paste your Travis CI token from here, https://travis-ci.org/profile/GITHUB_USERNAME/profile, into the Github Token text box.
- Check the Active check box.
Add a .travis.yml file to the Rails root directory, notice we are responsible for running the migrations,
# example_travisci_multi/.travis.yml language: ruby rvm: - 1.9.3 before_script: - rake db:migrate # uncomment this line if your project needs to run something other than `rake`: # script: bundle exec rspec spec
- Commit. Push to github. Travis CI will automatically run your tests.
- View your test status & results on Travis CI, https://travis-ci.org/GITHUB_USERNAME/REPO_NAME
Multiple ruby versions & database types
Now for some Travis CI power. Let’s test the Rails project against multiple databases and multiple ruby versions. We’ll need to change the following files,
# example_travisci_multi/.travis.yml language: ruby # creates 3 variable build maxtix. 1 each for a different RVM version rvm: - 2.0.0 - 1.9.3 - jruby-19mode # adds 3 variables to each build matrix. env: - DB=sqlite - DB=mysql - DB=postgresql # the result, 9 different build matricies. more about this, # http://about.travis-ci.org/docs/user/build-configuration/#The-Build-Matrix # add the extra shell commands to ensure the db exits, the # migrations have ben run, and the development env schema has # been applied to the test database. # before_script: - rake db:create - rake db:migrate - rake db:test:prepare # uncomment this line if your project needs to run something other than `rake`: # script: bundle exec rspec spec
We need to change how the database drivers are loaded to support MRI Ruby and JRuby database connectors. In brief, the database connector is decided by the travis shell variable,
ENV['DB'], defaulting to
sqlite. Notice the
mysql connection has double nested boolean logic to change the adapter name between ‘mysql’ for ruby and ‘mysql2’ for JRuby.
# example_travisci_multi/config/database.yml sqlite: &sqlite adapter: sqlite3 mysql: &mysql adapter: mysql<%= "2" unless ( ENV["TRAVIS_RUBY_VERSION"].include? "j" if ENV["TRAVIS_RUBY_VERSION"] ) %> username: root password: postgresql: &postgresql adapter: postgresql username: postgres password: min_messages: ERROR defaults: &defaults pool: 5 timeout: 5000 host: localhost <<: *<%= ENV['DB'] || "sqlite" %> development: database: example_travisci_multi_dev <<: *defaults test: database: example_travisci_multi_test <<: *defaults production: database: example_travisci_multi_prod <<: *defaults
Since MRI Ruby and JRuby use different database drivers, we need to conditionally select the appropriate adapter for installation in the Gemfile.
# example_travisci_multi/Gemfile source 'https://rubygems.org' gem 'rails', '3.2.13' group :assets do gem 'sass-rails', '~> 3.2.3' gem 'coffee-rails', '~> 3.2.1' gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' gem "rspec-rails" ## AND ADD THIS # group :development, :test do platforms :jruby do gem 'activerecord-jdbcsqlite3-adapter' gem 'activerecord-jdbcmysql-adapter' gem 'activerecord-jdbcpostgresql-adapter' gem 'jruby-openssl' end platforms :mri do gem 'sqlite3' gem 'mysql2' gem 'pg' end end