1

Rails Active Merchant Paypal Express (ouch…) and Cucumber

Testing paypal with cucumber (or any other test framework) is not that easy. First, because those frameworks prevent the server to request external urls (which is probably a good idea). The second reason is because you don’t have access to the paypal pages/responses directly.
For my project I’m using paypal express but I’m sure you can adapt this method to other gateways.

Paypal responses

To reproduce Paypal responses we need to copy them. The best way I found to do that is just to include some code in the active merchant functions to store the response (because active-merchant doesn’t provide the raw_response directly).
inside the active_merchant/billing/gateways/paypal/paypal_common_api.rb, I changed the commit function to

def commit(action, request)
  raw_response = ssl_post(endpoint_url, build_request(request),
    @options[:headers])
  response = parse(action, raw_response)
  File.open("paypal_response.xml","w") {|f| f.write raw_response.to_s }

It’d be a good idea to change the name of the file depending of the request paypal action. But for my need this simple hack is ok.
Then I need to capture those responses (using the rails server in development mode) by navigating through my application payment process.

I changed each time the file name to match the requestion_action and I got

  • paypal_checkout_ok_response.xml
  • paypal_details_ok_response.xml
  • paypal_purchase_ok_response.xml

Now we have our paypal responses

Using Webmock

Webmock is a powerful tool to simulate external calls from your server. You specify url and the response body and when your server try to reach this url it gets this body.

Given /^paypal will authorize payment$/ do

  # Because active_merchant will redirect the client 
  # to the http://sandbox.paypal.com/cgi-bin/webscr
  # We need to define this route to prevent the "undefined route"
  Rails.application.routes.append do
    match '/cgi-bin/webscr' => "home#index"
  end
  Rails.application.reload_routes!

  stub_request(:post, "https://api-3t.sandbox.paypal.com/2.0/").
  with(:body => /.*SetExpressCheckout.*/).
  to_return(:body => File.new(File.join(
    File.dirname(__FILE__),
    "../webmock_stubs/paypal_checkout_ok_response.xml")))

  stub_request(:post, "https://api-3t.sandbox.paypal.com/2.0/").
  with(:body => /.*GetExpressCheckoutDetails.*/).
  to_return(:body => File.new(File.join(
    File.dirname(__FILE__),
    "../webmock_stubs/paypal_details_ok_response.xml")))

  stub_request(:post, "https://api-3t.sandbox.paypal.com/2.0/").
  with(:body => /.*DoExpressCheckoutPayment.*/).
  to_return(:body => File.new(File.join(
    File.dirname(__FILE__),
    "../webmock_stubs/paypal_purchase_ok_response.xml")))

end

Simulating the paypal form process

I simplified this one to the single following step.

When /^fills the paypal informations$/ do
  token = "EC-3FW39378TY823225R"
  payer = "9K4KRSTUSZDGU"
  visit(new_order_url(:protocol => "https") + 
    "?cart=#{@cart.id}&token=#{token}&PayerID=#{payer}")
end

This is what your server is supposed to receive when the payer fills the paypal page. The token and payer number are taken from the paypal response I logged before.
Because there is no real interaction between the server and paypal the Token is always valid.

What’s next?

Prepare the failed response and test them

0

Top 3 Zerg tips – Part 2 – Scooting

sc2-tumors-mini.jpg

After the Zerg tips – Part 1 about queens, today is for the scooting.

Zergs have 2 advantages, they have the fastest unit at the beginning of the game and a flying (ok… very slow) one. You must research the gling speed early enough to get a good map control and scoot the enemy soon.
The positions of the overlords are really important, because they can scoot your enemy without being discovered which give you a big advantage.

Where to send your overlords

This mainly depends of your preferences but their are some rules that will help you if you have no idea.

  1. On the high hills, to prevent them from being seen… the best is between your base and the enemy base to see them coming from the front.
  2. Around your base on the flying zones. This is mainly to scoot any ship trying to backstab you. It is always better to loose an overlord and see your enemy coming (if they have air-attack units) than discovering them in your base.
  3. Behind, close to your enemy base(s). This one has 2 purposes, see them expanding (the best is to place your overlord to scoot the mineral fields) and scoot them in the middle of the game where 2 glings can’t enter in their base anymore. In that case, sacrifice your overlord (it is better to have the speed) to go over his main base and see his buildings/units.

sc2-tumors7.jpg

Expanding your creep

I’ve seen too many zergs (even me :p) playing the whole game without using the creep. This is a mistake. The creep gives you more than just unit speed, it gives you the scoot you need all around your base and all over the map.
What a pleasure to see every move of your ennemy. There are different ways to expand it but you really need an extra queen if you want to do it well.

  1. Spawn many tumors at the same place, the creep will increase faster and you will have the possibility to spawn the next creep tumor quickly at the farther position.
  2. (In Middle Game) Use your overlords to spawn some creep on the way to your enemy, and use 1 queen to spawn a tumor under every overlord… You’ll get in 10s a path from your base the enemy

This is it for today. Tell me if it helped you.

0

1and1 Geotrust certificate with nginx

padlock_green_117785.jpg

Adding https to my website (http://www.commemora.fr) was not that simple. For many reasons, the first one is that some certificates are valid for one subdomain and other for fulldomain.
But once I got my certificate right, I had to install it into my configuration.

Nginx is like apache, you just need add the ssl key and certificate in a protected folder and add them in your server configucation

  listen                 443 default ssl;
  ssl_certificate        /etc/nginx/keys/myporject.crt;
  ssl_certificate_key    /etc/nginx/keys/myporject.key;

And bingo… chrome is showing me the little green padlock. Everything is perfect!
Except… Firefox and IE are complaining about GeoTrust. Their intermediate certificate is missing.

Nagivating all over the pages on the GeoTrust website I finally found the Intermediate certificates (here they are https://knowledge.geotrust.com/support/knowledge-base/index?page=content&id=AR1421)
And from there, Nginx is a bit different to Apache, you can’t specify the chain certificate but you have to append it to your current certificate.

cp myproject.crt myproject.chained.crt
cat  geotrust-intermediate-first.crt >> myproject.chained.crt 
cat  geotrust-intermediate-second.crt >> myproject.chained.crt

Don’t forget to add the first and the second certificate. One without the other is not working (I did the test!!)
And also be sure to add your certificate first (if not nginx will complain your key doesn’t match the certificate)

You just need to change your nginx configuration to use the new chained certificate

  listen                 443 default ssl;
  ssl_certificate        /etc/nginx/keys/myporject.chained.crt;
  ssl_certificate_key    /etc/nginx/keys/myporject.key;

The result is there : https://www.commemora.fr

0

Top 3 Zerg tips – Part 1 – The queen


Make many queens and now how to use them

Queen Game StarCraft II

There is nothing as important as the queens. Providing larvas, creep tumors, heal and defense, they are always useful.

  • It is important to get them early. Not only because you need as many larvas as possible at the beginning of the game but also they will accumulate some energy to save you in bad situations (heal the crawlers or the other queens is a real bonus).
  • More you have queens, more you can defend against small aggression like few zealot in your base, reapers or hellions, ans also against air aggression (pheonix, banshees, terran drops…).
  • Always deploy your creep tumor and more you have queens, easier it is to do that

To manage your queens it is useful to have a dedicated shortcut (mine is 4, the hatcheries are in 5).

The larvas queen tip

Queen Larvas Game StarCraft II

If you want to inject larvas quikly into all your bases you can use the *backspace* key to go through each of your hatcheries. And to make it better, because the backspace is a bit far from other keys, bind one mouse button to *backspace* and like this you get:
1. press shortcut 4
2. press shit+v (v is my shortcut for the larvas)
3. press your mouse button for backspace and click on the middle of the map
4. do the 3 again and again

you can inject larvas into many hatcheries (even 20 if you have) in less than a second!

Other solution, the minimap injection

for those you can bind a key on their mouse there is another tip using the minimap. Tor this one select all your queens (key 4) and press shift + v, and click on all the hatcheries on the minimap

0

Rails 3.1 Staging Environment with Capistrano

Why a Staging Environment?

I arrived to a point where I couldn’t deploy anymore without having a staging environment before. Why? Because there are too many differences between my development and production environment like SSL implementation, precompiled Assets, Http & Rails servers are differents too and also because sometime you need to test your deployment script. Most of the time you can’t handle those during your tests. This is why you need a pre-production stage.
This is the way I do it. Maybe not the best but at least it works fine. For this deployment I use the gems ‘capistrano’ and ‘capistrano-ext’ (for the multistage support)

Setup a staging server

The first step is to have a pre-production server (in my case, it will be another Virtual machine on my computer running a fresh ubuntu with a copy of my real production server libraries). It is important to match as much as possible the production server (however, if you can’t easily copy the configuration of your production, it’s ok if there are some differences). Make sure you have at least of the libraries you need for your project and the deployment (if there are some missing, you’ll notice it and solve it after you first deployments)

Prepare rails staging environment

Because Staging is not Production you need to set a different environment environments/staging.rb. If you can make it a copy of the production.rb it is the best. Now we have to create a deploy folder in which we gonna add the environment specific deployment files.

production.rb

server 'www.myprodserver.com', :app, :web, :db, :primary => true
set :domain, "myprodserver.com"
set :rails_env, "production"
set :backup_server, "backup.mybackupserver.com"

staging.rb

server 'stagserver', :app, :web, :db, :primary => true  #you can use ip address
set :domain, "stageserver.com" #I configured my hosts to match the good ip
set :rails_env, "staging"
set :backup_server, "192.168.1.4"

and configure the deploy.rb

set :stages,                %w(production staging)
set :default_stage,         "staging"
set :capistrano_extensions, [:multistage, :git, :mysql, :rails, :unicorn, :servers]

$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path.
require "rvm/capistrano"                                # Load RVM's capistrano plugin.
require "bundler/capistrano"
require "whenever/capistrano"
require 'capistrano/ext/multistage'
...

We also need to generate the nginx configuration for the staging and deployment (I like it to be generated like this I don’t have to configure the server independently)
Still inside the deploy.rb

namespace :nginx do
  desc "Generate nginx configuration"
  task :generate_site, :roles => :web, :except => { :no_release => true } do
    require 'erb'
    template = File.read(File.join(File.dirname(__FILE__), "deploy", "#{application}.nginx.conf.erb"))
    result = ERB.new(template).result(binding)
    put result, "#{current_path}/config/deploy/#{domain}", :mode => 0644
  end
end

It will generate my nginx configuration based on the erb file included in the deploy folder (I use nginx and Unicorn for my prod/staging)

upstream <%= application %> {
  server unix:/tmp/<%= application %>.socket fail_timeout=0;
}

server {
  listen          80;
  listen          443;
  server_name     <%= domain %> *.<%= domain %>;
  rewrite ^       http://www.<%= domain %>$request_uri? permanent;
 }

server {
  listen          80;
  server_name     www.<%= domain %>;
  root            <%= current_path %>/public;
  access_log      /var/log/nginx/<%= application %>_access.log;
  rewrite_log      on;

  location / {
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    if (!-f $request_filename) {
      proxy_pass  http://<%= application %>;
      break;
    }

    client_max_body_size       10m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
  }

}

server {
  listen          443 default ssl;
  server_name     www.<%= domain %>;
  root            <%= current_path %>/public;
  access_log      /var/log/nginx/<%= application %>_access_ssl.log;
  rewrite_log      on;
  
  ssl_certificate    /etc/nginx/keys/changeit_toyour_ownkey.crt;
  ssl_certificate_key    /etc/nginx/keys/changeit_toyour_ownkey.key;

  location / {
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header   X_FORWARDED_PROTO https;

    if (!-f $request_filename) {
      proxy_pass  http://<%= application %>;
      break;
    }

    client_max_body_size       10m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
  }
}

Capistrano multistage will take care of reading the good environment file inside the config/deploy folder.
From now we have our production deploy.rb working also for staging… and to be safe, default deploy will deploy on the staging server.

Deploy it

For staging:

cap deploy

For production:

cap production deploy

It is the configuration I actually use for my websites ( http://www.commemora.fr a french website about commemoration, http://www.kakimovies.com, another site about movies and http://japon.crystalin.fr for my personnal rails photoblog)

I hope it helped you.

0

Cucumber, the new way

Cucumber Making BDD fun2

As the Rails community might have noticed already Cucumber changed a little since the version 1.1.0. It is no longer including the web_steps.rb neither paths.rb. When I first conclusion was « What the hell is that? How am I gonna write some cool tests? » I then started to read his post and understood it.

At least he provides a simple example how cucumber tests should be written which made me write some of mine.From there I tried to follow the rules and rewrite my tests

  Scenario Outline: Visitor can create account
    Given the visitor "<name>" with email "<email>" and password "<password>"
    When he goes to the account creation page
    And fills the account form
    Then he should be in the database
    Then he should receive a notice containing ""
  Examples:
    | name              | email                   | password    |
    | Silvain Dupont    | silvain_dupont@net.com  | 123456      |

It is more readable than the *fill this with that*. It is doing the same tests as previously but is more readable. The description of the steps for this tests are (inside users_steps.rb)

User creation module

module UserSteps
  def new_user(name, options = {})
    options = {
      :email => "#{name.parameterize}_email@test.com",
      :password => "#{name.parameterize}_password",
    }.merge options
    User.new(:name => name, :email => options[:email], :password => options[:password], :password_confirmation => options[:password])
  end

  def create_user(name, options = {})
    user = new_user(name,options)
    user.save!
    user
  end
end
World(UserSteps)

User Steps

Given /^the visitor "([^"]*)" with email "([^"]*)" and password "([^"]*)"$/ do |name, email, password|
  @user = new_user(name, :email => email, :password => password)
end

Given /^the visitor "([^"]*)"$/ do |name|
  @user = new_user(name)
end

Given /^the user "([^"]*)" has an account$/ do |name|
  @user = create_user(name)
end

When /^he goes to the account creation page$/ do
  visit new_user_url
end

When /^fills the account form$/ do
  within("#new_user") do
    fill_in 'user_name', :with => @user.name
    fill_in 'user_email', :with => @user.email
    fill_in 'user_password', :with => @user.password
    fill_in 'user_password_confirmation', :with => @user.password
    find('input[type="submit"]').click
  end
end