Here at PlataformaTec we like to use Capybara for acceptance tests. Recently we have discovered the custom selectors feature in Capybara and we would like to share with you how that feature helped us to improve our tests.
Sometimes we need to implement features that involves showing some ordered items to the user, like a ranking feature. The HTML for a feature like that could be:
<ol id="overall-ranking"> <% @top_users.each do |user| %> <li><%= user.name %></li> <% end %> </ol> |
The acceptance tests for this ranking could be written as follows:
scenario "The user can see an overall ranking" do Factory(:user, :name => "Hugo", :score => 5000) Factory(:user, :name => "Ozaki", :score => 3000) Factory(:user, :name => "João", :score => 4000) visit overall_ranking_path within("#overall-ranking") do find(:xpath, './/li[1]').text.should match("Hugo") find(:xpath, './/li[2]').text.should match("João") find(:xpath, './/li[3]').text.should match("Ozaki") end end |
Generally, I don’t like to see those XPath selectors inside my acceptance tests. And sometimes it can get really ugly! So, in order to improve our tests, we can create a custom selector with Capybara as follows:
# spec/spec_helper.rb RSpec.configure do |config| Capybara.add_selector(:li) do xpath { |num| ".//li[#{num}]" } end end |
After that, we can refactor our test as shown below:
scenario "The user can see an overall ranking" do Factory(:user, :name => "Hugo", :score => 5000) Factory(:user, :name => "Ozaki", :score => 3000) Factory(:user, :name => "João", :score => 4000) visit overall_ranking_path within("#overall-ranking") do find(:li, 1).text.should match("Hugo") find(:li, 2).text.should match("João") find(:li, 3).text.should match("Ozaki") end end |
If you wanna know more about Capybara’s custom selectors, check its README.
And you? Any tips about using Capybara or improving your acceptance/integration tests?
Tags: capybara, tests
Posted in English | 6 Comments »
Nesse sábado (29/05/2010) eu fiz uma palestra sobre Rails 3 no evento Ruby e Rails no Mundo Real 2010. O evento foi muito bom, tendo cerca de 200 pessoas participando. Queria agradecer a todos que estavam lá para ver minha palestra e agradecer também aos elogios, muito obrigado.
Seguem meus slides:
E o vídeo da minha palestra, que foi feito pelo @agaelebe.
Posted in Português | 5 Comments »
I’ve been playing a lot with Rails 3 lately, it’s completely awesome! However, we don’t have any Rails 3 app in production at the moment, all projects that Plataforma has been doing for its clients so far are using Rails 2.3.5. Since I was already having fun with Rails 3, I thought I should also give ruby 1.9 a try. Ok, so how could I have Rails 2.3.5, Rails 3, ruby 1.8.7 and ruby 1.9 in my machine without going crazy? The answer is RVM (Ruby Version Manager)!
RVM is an awesome tool that gives you the power to have as many rubies in your machine as you want, and the best of all, all versions are isolated, no conflicts at all. In order to install it, follow the instructions inside RVM’s site. After that, I installed ruby 1.9.1 through RVM with rvm install 1.9, installed all the gems necesssary to play with Rails 3 (gem install rails --pre) and then, I could start to play.
I was playing with that configuration successfully until the moment I got a segmentation fault error. Other people got the same error too. Thankfully the problem didn’t last too long, this was one of these moments which I was very happy for having a Rails Core member in my team (@josevalim). He told me that Rails 3 doesn’t support ruby 1.9.1, actually, it’s supporting ruby 1.9.2! So, I needed to install a new ruby version, and install all Rails 3 gems again, damn it! But, I was fortunate enough for being using RVM.
In order to install Ruby 1.9.2-head and Rails 3 gems, all I needed to do was:
- Update my RVM:
rvm update --head - Install ruby 1.9.2 head:
rvm install 1.9.2-head - Create a Rails 3 RVM gemset:
rvm --create use 1.9.2-head@rails3 - Copy my already installed Rails 3 gems to my new RVM gemset within my ruby 1.9.2:
rvm gemset copy 1.9.1 1.9.2-head@rails3
That’s all! After that, I was back to the game! Man, RVM is awesome!!!
Be sure to have a look at a Wayne’s gist about how to install Rails 3 with RVM, and, check out RVM’s Gemsets feature, it’s very useful.
And you, do you have any tips about dealing with many versions of ruby and/or Rails, or about RVM?
Tags: rails, rvm
Posted in English | 18 Comments »
So, you already did the right choice of using Delayed Job for your background processing, great! But, how are you going to be certain that your background processing will still be happening while you are sleeping? And if your Delayed Job process goes down, are you going to wake up in the dawn e restart it manually? I wouldn’t do that, I really appreciate my sleep. So, what’s the solution?
As rubyists and railers, we already know there are solutions, like God, that do this job for us. However, there are another solutions, like Bluepill. Bluepill is a process monitoring tool like God, but, unlike God, it doesn’t have memory leak, according to its authors.
Well, as I don’t want to wake up in the dawn to restart my Delayed Job process, and neither I want to restart my God process because of memory leaking, I decided to use Bluepill. But, how I use Bluepill to monitor my Delayed Job process?
In order to configure Bluepill to monitor Delayed Job, and use Capistrano to automate some tasks, we have basically 4 steps:
- Install and configure Delayed Job
- Install and configure Bluepill
- Write a Capistrano Recipe for Bluepill
- Set some stuff in /etc/sudoers
Let’s take a look at each step.
Installing and configuring Delayed Job
Installing and configuring Delayed Job is super simple, just read the project’s README, which is very clear. I also recommend watching the RailsCast episode about Delayed Job, there is some good information there, like using the Delayed Job CollectiveIdea’s fork, instead of the original repo’s version.
Installing and configuring Bluepill
There’s no secret in installing Bluepill too, you just need to read the project’s README and follow its steps.
In the confiuration part, you can see all the options in the README too. In my case, the configuration file is at RAILS_ROOT/config/production.pill.
Bluepill.application("my_app") do |app| app.process("delayed_job") do |process| process.working_dir = "/home/deploy/my_app/current" process.start_grace_time = 10.seconds process.stop_grace_time = 10.seconds process.restart_grace_time = 10.seconds process.start_command = "ruby script/delayed_job -e production start" process.stop_command = "ruby script/delayed_job -e production stop" process.pid_file = "/home/deploy/my_app/shared/pids/delayed_job.pid" process.uid = "deploy" process.gid = "deploy" end end |
However, I had a little problem between the interaction of Bluepill and Delayed Job. Delayed Job is not interpreting very well the -e production flag. You can see more details about that in an issue I opened.
The first solution I thought was to use RAILS_ENV=production ruby script/delayed_job start, however, for some reason that I don’t know exactly, it didn’t work.
So, the solution I came up with was to modify the file in RAILS_ROOT/script/delayed_job to the following one:
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env ruby # TODO improve the line of code below # The line below is just a hack while we wait the delayed job guys answer the following issue # http://github.com/collectiveidea/delayed_job/issues#issue/38 ENV['RAILS_ENV'] ||= "production" require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) require 'delayed/command' Delayed::Command.new(ARGV).daemonize |
As the -e production was not being interpreted properly by Delayed Job, I’m setting manually the RAILS_ENV to production (line 6), therefore I’m supposing that you are using Bluepill to monitor processes that are in a production environment.
Capistrano recipe for Bluepill
In order to automate the start and stop Bluepill’s tasks, I wrote the following capistrano’s recipe:
# deploy credentials set :user, "deploy" set :deploy_to, "/home/deploy/#{application}" set :use_sudo, false set :rails_env, "production" # Bluepill related tasks after "deploy:update", "bluepill:quit", "bluepill:start" namespace :bluepill do desc "Stop processes that bluepill is monitoring and quit bluepill" task :quit, :roles => [:app] do sudo "bluepill stop" sudo "bluepill quit" end desc "Load bluepill configuration and start it" task :start, :roles => [:app] do sudo "bluepill load /home/deploy/my_app/current/config/production.pill" end desc "Prints bluepills monitored processes statuses" task :status, :roles => [:app] do sudo "bluepill status" end end |
Note that instead of using the run capistrano’s method, I’m using the sudo method. I’m doing this because the bluepill command must be run as root. And that, takes us to the next topic.
/etc/sudoers
Since I need to run the bluepill command as root, should I change from set :user, "deploy" to set :user, "root"? I think it’s not a good idea, we don’t like to give root access to anything, even to deployment. So, what should I do? It’s simple, you just need to edit your sudoers file.
In order to do this, you need to use the visudo command to open and edit the /etc/sudoers file. Once with the file opened, just add the following line to the end of the file:
deploy ALL=(ALL) NOPASSWD: /usr/local/bin/bluepill
Now, you’re done, the deploy user already can do sudo bluepill without giving any password. Problem solved without opening security holes.
After these 4 steps, you’re ready to sleep at night without worrying about your Delayed Job process. And, if you want to know the status of the monitored processes by Buepill, you just need to run the following capistrano task in your local machine:
cap bluepill:status
And you, what are your solutions to sleep in peace?
Update: if are having trouble with restarting Bluepill with Capistrano, take a look at this.
Tags: bluepill, capistrano, delayed job, process monitoring
Posted in English | 12 Comments »
Então você já fez a feliz escolha de tratar seu processamento em background com Delayed Job, ótimo! Mas como ter certeza que esse processamento vai continuar acontecendo enquanto você estiver dormindo? E se o o processo do Delayed Job cair, você vai acordar de madrugada e levantá-lo na mão? Eu não faria isso, gosto do meu sono. Qual a solução então?
Não é nenhuma novidade para nós, rubyistas e railers, que existem soluções como o God para fazerem o trabalho de monitoramento de processos. No entanto, existem outras soluções, como o Bluepill. O Bluepill é uma ferramenta de monitoramento de processos assim como o God, mas diferente dele, não tem memory leak, segundo seus autores.
Bem, como não quero acordar de madrugada para levantar meu processo do Delayed Job na mão, e também não quero ficar restartando um processo do God por causa de memory leak, resolvi usar o Bluepill. Mas como uso o Bluepill para monitorar o Delayed Job?
Para configurar o Bluepill para monitorar o Delayed Job, e usar o Capistrano para automatizar algumas tarefas, temos basicamente 4 passos:
- Instalar e configurar o Delayed job
- Instalar e configurar o Bluepill
- Escrever a receita de capistrano para o Bluepill
- Setar algumas coisas do arquivo /etc/sudoers
Vamos dar uma olhada em detalhes em cada passo.
Instalação e configuração do Delayed Job
Instalar e configurar o Delayed Job é super simples, basta ler o README do projeto, que está bem claro. Recomendo também assistir ao RailsCast sobre o Delayed Job. Foi de lá que tirei a informação de usar o fork do Delayed Job da Collective Idea ao invés da versão do repositório original.
Instalação e configuração do Bluepill
Instalar o Bluepill também não tem muito segredo, basta você ler o README do projeto e seguir os passos que estão descritos lá.
Na parte da configuração, você pode ver as opções também no README do projeto. No meu caso, esse arquivo está em RAILS_ROOT/config/production.pill.
Bluepill.application("my_app") do |app| app.process("delayed_job") do |process| process.working_dir = "/home/deploy/my_app/current" process.start_grace_time = 10.seconds process.stop_grace_time = 10.seconds process.restart_grace_time = 10.seconds process.start_command = "ruby script/delayed_job -e production start" process.stop_command = "ruby script/delayed_job -e production stop" process.pid_file = "/home/deploy/my_app/shared/pids/delayed_job.pid" process.uid = "deploy" process.gid = "deploy" end end |
No entanto, eu tive um pequeno problema com a interação do Bluepill e o Delayed Job. Ao passar a flag -e production para o Delayed Job, ele não a estava interpretando direito. Você pode ver mais detalhes sobre isso numa issue que abri no repo do Delayed Job.
A primeira solução que pensei, foi usar RAILS_ENV=production ruby script/delayed_job start, no entanto por algum motivo que ainda desconheço, isso não funcionou.
A solução que cheguei então para resolver esse problema, foi modificar o arquivo que está em RAILS_ROOT/script/delayed_job para o seguinte:
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env ruby # TODO improve the line of code below # The line below is just a hack while we wait the delayed job guys answer the following issue # http://github.com/collectiveidea/delayed_job/issues#issue/38 ENV['RAILS_ENV'] ||= "production" require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) require 'delayed/command' Delayed::Command.new(ARGV).daemonize |
Como a flag -e production não estava sendo interpretada direito no Delayed Job, estou setando na mão o RAILS_ENV para production (linha 6), portanto estou supondo que você só está usando o Bluepill para monitorar processos do Delayed Job em environment igual a production.
Receita do Capistrano para o Bluepill
Para automatizar as tarefas de ligar e desligar o Bluepill, escrevi a seguinte receita de capistrano:
# deploy credentials set :user, "deploy" set :deploy_to, "/home/deploy/#{application}" set :use_sudo, false set :rails_env, "production" # Bluepill related tasks after "deploy:update", "bluepill:quit", "bluepill:start" namespace :bluepill do desc "Stop processes that bluepill is monitoring and quit bluepill" task :quit, :roles => [:app] do sudo "bluepill stop" sudo "bluepill quit" end desc "Load bluepill configuration and start it" task :start, :roles =>[:app] do sudo "bluepill load /home/deploy/my_app/current/config/production.pill" end desc "Prints bluepills monitored processes statuses" task :status, :roles => [:app] do sudo "bluepill status" end end |
Note que ao invés de usar o método run do capistrano, estou usando o método sudo. Isso porque o comando bluepill deve ser rodado como root. Isso nos leva para o próximo tópico.
/etc/sudoers
Já que eu preciso rodar o comando bluepill como root, vou ter que mudar o meu set :user, "deploy" para set :user, "root"? Acho melhor não, não gostamos de dar acesso root para qualquer coisa, mesmo para deployment. Então, como fazer? Simples, basta editar seu arquivo de sudoers.
Para isso, você precisa usar o comando visudo para abrir e editar o arquivo /etc/sudoers. Uma vez com o arquivo aberto, adicione a seguinte linha no final do arquivo:
deploy ALL=(ALL) NOPASSWD: /usr/local/bin/bluepill
Pronto, agora o usuário deploy já pode fazer sudo bluepill sem precisar de senha. Problema resolvido sem colocar a segurança da sua máquina em risco.
Depois de ter feito esses 4 passos, você está pronto para dormir a noite sem se preocupar com seu processo do Delayed Job. E quando quando quiser saber como está o status dos seus processos monitorados, basta usar a seguinte task do capistrano na sua máquina local:
cap bluepill:status
E você? Quais soluções você usa para dormir em paz?
Update: Se você está tendo problemas em restartar o Bluepill com o capistrano, dê uma olhada aqui.
Posted in Português | Comments Off
O Rails for Kids foi uma maratona beneficente de palestras on-line realizada no dia 12/09/2009 que contou com grandes nomes da comunidade Ruby on Rails do Brasil e de fora. Nós da Plataforma Tecnologia fomos representados por mim (Hugo Baraúna) e pelo George Guimarães.
A qualidade do evento foi surpreendente, ainda mais quando levamos em consideração que ele foi realizado totalmente on-line. Na minha opinião, a organização do Rails for Kids foi excelente pois juntou um respeitado time de palestrantes, utilizou uma ferramenta para apresentações online/e-learning muito boa e teve presença em peso da comunidade. Parabéns ao Carlos Eduardo pela organização! Eventos assim são sempre bem-vindos! =)
Mas para aqueles que não puderam participar do evento, não se preocupem. Ainda há uma chance: as palestras foram gravadas! Basta entrar no site do Rails for Kids e fazer uma simbólica doação. Você ajuda quem precisa e assiste a palestras de primeira qualidade. É um benefício em dose dupla! =D
Se não puder ajudar com doações, divulgue. Vale lembrar que o objetivo maior é ajudar crianças carentes.
Valeu pessoal!
obs.: para ler um bom resumo das palestras do evento, dê uma olhada nesse post do Carlos Antônio, da para ter uma ótima idéia!
Posted in Português | Comments Off

All
English only
Em português apenas
