Monday, October 14, 2013

Testing Responsive web design with Rspec

Recently I am working on an application where we have used zurb foundation for responsive web design. We have separated all devices screen broadly into three categories as follows,

1. small : Screen width upto 590.
2. medium : Screen width upto 1025.
3. large : Screen width uptp 1280.

Very soon we will add new category,
4. xlarge : above 1280+ ;)

Now all things are fine, but until you didn't write acceptance test, you can't make sure that your design is working fine for all screen.

Before taking responsive web design into consideration, we have already written feature specs using rspec + capybara (selenium).

So here we want handy configuration which will not affect existing feature spec and should treat existing specs meant to be written for large screen.

So here is, how I have added configuration for my rspec suite to target testing responsive design.


With above configuration, if you write any feature spec without :device_size then it will run that spec against 'large' screen. And if you want to write a spec for 'small' and 'medium' devices you can write by using metadata 'device_size => :small' or 'device_size => :medium'
e.g.
  feature "XYZ" do
    scenario "abc", :js => true do
      # spec with default screen size i.e large
    end 

    scenario "abc", :js => true, :device_size => :small do
      # spec with small screen size
    end 
  end
With the help of 'config.include ScreenSize, :type => :feature' you can directly change screen size into example.
e.g.
  feature "XYZ" do
    scenario "abc", :js => true do
      set_screen_size(:medium)
      # spec with default screen size i.e large
    end 
  end
If you want to some special configuration based on device size you can do that using,
  config.before(:each, :device_size => :small) do
    # special configuration .........
  end
TODO :
I want to split a test suite into feature/small/*.rb for small devices, feature/large/*.rb for large devices and so on.. and apply specific metadata configuration based on type of suite.

References :
http://www.blaulabs.de/2011/11/22/acceptance-testing-with-responsive-layouts

Sunday, September 22, 2013

Capybara wait for ajax call to finish

TL;DR: Before capybara 2.0.0, wait_until method was available which can be used for wait for ajax call to finish. In capybara 2.0.0, wait_until method is removed as it is not needed and was creating confusion. Capybara automatically waits for elements to appear or disappear on the page. If you do something like find("#foo"), this will block until an element with id “foo” appears on the page, as will has_content?("bar"), click_link("baz") and most other things you can do with Capybara.

Since today morning I was facing very strange issue with capybara feature spec. One of my spec was failing with following error.
spec:
    scenario "can create comment" do
      user =  FactoryGirl.create(:user, :email => "p@abc.com")
      post = FactoryGirl.create(:published_post)

      login(user)

      visit post_path(post)

      page.find('#comment_body').set("This is my comment")
      keypress_script = "var e = $.Event('keypress', { keyCode: 13 }); $('#comment_body').trigger(e);"
      page.execute_script(keypress_script)
   
      page.should have_text("This is my comment")
      page.should have_link('Reply')
      page.should have_link('Edit')
      page.should have_link('Destroy')
    end

       expected to find text "This is my comment" in "BROWSE CATEGORIES FORMATS MY PREGNANCY VOICES SERVICES POST TAGS MyText About Author1 — A brief write up about the author will come here. This will not exceed more than 250 characters. Give us your opinion. Discuss it with people like you. Javier Huel - This is my comment 0 likes | 0 replies LIKE | Reply | Edit | Destroy SIMILAR POSTS about us | our team | our vision | give feedback | privacy policy | terms of use | best viewed in | careers | site map © 1998–2013 ABC, Inc. All rights reserved."
     # ./spec/features/commets_spec.rb:42:in `block (3 levels) in ' 

Now in above error, I am clearly able to see that the text is present in page, but still it is not able to match it.

To quickly understand what is happening, I have used pry. On pry prompt, just verified expectation again and this time it is evaluated true.
[1] pry(#)> page.should have_text("This is my comment")
=> true 

Means, here capybara was not waiting for ajax call to finish.

So I have googled for "capybara + wait for ajax call to finish" and found solution to use "wait_until" method.

When I have tried this method, I got into another error,
Failure/Error: wait_until do
     NoMethodError:
       undefined method `wait_until' for #
     # ./spec/features/commets_spec.rb:41:in `block (3 levels) in '
While googled more, I found strong discussion of Jonas Nicklas and found that wait_until is removed from capybara 2.0.0 ;(.

Alternatively, I found how to implement "wait_until" back into capybara.

But in same discussion Jonas Nicklas has posted a link of his blog post where he has explained about why this decision was reached. Also he has mentioned how we can wait for ajax call to modify DOM.

So, my spec changed to,
    scenario "can create comment" do
      user =  FactoryGirl.create(:user, :email => "p@abc.com")
      post = FactoryGirl.create(:published_post)

      login(user)

      visit post_path(post)

      page.find('#comment_body').set("This is my comment")
      keypress_script = "var e = $.Event('keypress', { keyCode: 13 }); $('#comment_body').trigger(e);"
      page.execute_script(keypress_script)
   
      page.should have_selector(".comment", :text => "This is my comment")
      page.should have_link('Reply')                         # Subsequent call also passed due to have_selector
      page.should have_link('Edit')
      page.should have_link('Destroy')
    end
 
and which is passing. ;)

References :
https://groups.google.com/forum/#!topic/ruby-capybara/qQYWpQb9FzY
http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara
https://gist.github.com/KevinTriplett/5087744

Monday, May 6, 2013

Ubuntu 13.04 + XPS Dell + sound is not working

Recently I have upgraded my Ubuntu OS from 12.10 to 13.04 on my Dell XPS.

But suddenly I faced issue with my sound. I am not able to get sound form my machine.

After googling, I found solution for Dell Vostro, but after some time I found for dell xps too. I tried solution on my Dell box and my sound is back.

Here is the solution,
sudo gedit /etc/modprobe.d/alsa-base.conf
Add following line at the bottom of a file
options snd-hda-intel model=dell-bios
But don't forget to reboot your machine.
References :
http://askubuntu.com/questions/288503/vostro-3560-sound-is-not-working-after-upgrade-to-ubuntu-13-04
http://ubuntuforums.org/showthread.php?t=1457676

Saturday, September 22, 2012

Rails 4 - Transaction isolation level


After long time I am writing small post, as now a days not able manage a time or you can say I am just working ;)

TL;DR - In Rails 4, Jon Leighton has added a support for specifying transaction isolation level. This transaction level we can pass when starting transaction(or you can say while calling transaction method)

Note : This blog post is copied from Jon Leighton commits, which he did in a rails repository

Before continuing reading this post, it will be good if you read about Transaction Isolation over here.

Isolation is a property that defines how/when the changes made by one operation become visible to other concurrent operations. Isolation is one of the ACID (Atomicity, Consistency, Isolation, Durability) properties.

Highlevel of Isolation does affect on Concurrency property of ACID, as it require to use locks or multiversion concurrency control.

Anyways here is a documentation which Jon Leighton has added in rails trank.

If your database supports setting the isolation level for a transaction, you can set it like so:

Post.transaction(isolation: :serializable) do
  # ...
end

Valid isolation levels are:
* `:read_uncommitted`
* `:read_committed`
* `:repeatable_read`
* `:serializable`

You should consult the documentation for your database to understand the semantics of these different levels:

* http://www.postgresql.org/docs/9.1/static/transaction-iso.html
* https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html

An `ActiveRecord::TransactionIsolationError` will be raised if:
* The adapter does not support setting the isolation level
* You are joining an existing open transaction
* You are creating a nested (savepoint) transaction

The mysql, mysql2 and postgresql adapters support setting the transaction isolation level. However, support is disabled for mysql versions below 5, because they are affected by a bug (http://bugs.mysql.com/bug.php?id=39170) which means the isolation level gets persisted outside the transaction.
References :
http://en.wikipedia.org/wiki/Isolation_(database_systems)
http://www.postgresql.org/docs/9.1/static/transaction-iso.html
https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
https://github.com/rails/rails/commit/392eeecc11a291e406db927a18b75f41b2658253

Sunday, July 1, 2012

bundle install +
tar_input.rb:49:in `initialize': not in gzip format (Zlib::GzipFile::Error)

This is one of the pending post since 6 month, thought it might helpful to some people.

Today on production server our system team found very strange issue with REE and bundler which lead production server was down for 20 min. This issue did not occur on test (Since on test and production have different version of REE)

Issue is as follows,


Issue was new to me, so I started digging into it using the almighty google.

The solution which I found on net was not applicable since we couldn't afford a downtime.

Issue is actually with ruby-enterprise-1.8.7-2010.02. Which is fixed in ruby-enterprise-1.8.7-2011.01 as described in release note.

http://blog.phusion.nl/2011/02/12/ruby-enterprise-edition-1-8-7-2011-01-released/

But we don't have a time to upgrade REE at this point. So I digged into it and found temporary solution described here.

http://stackoverflow.com/questions/2494659/strange-bundler-error-tar-input-rb49in-initialize-not-in-gzip-format-zlib


Basically you have to clear you gem cache either you are use rvm or not. so I have simply deleted content from my gems folder
like,
sudo rm -rf /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/cache/

And this worked !!!....

Sunday, February 12, 2012

Configure Repository In Redmine

As Rubyist, most of us we use Redmine for Project Management and git for source code management. Written using the Ruby on Rails framework, it is cross-platform and cross-database. Redmine is open source and released under the terms of the GNU General Public License v2 (GPL).

Git is a free & open source, distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

Redmine provides many features out of that is SCM integration (SVN, CVS, Git, Mercurial, Bazaar and Darcs), which I going to explaing you in this blog post.

I am explaning this because, many time we do a code review for team members. Also some time we need to review a perticuler fix done for any bug. At that time it is very difficult to go through a git log.

So it will be great to use to redmine for this, were we can attach a code to feature or bug and even from git log to issue.

Redmine has this great feature, http://www.redmine.org/projects/redmine/wiki/RedmineRepositories#Repository-user-mapping

Now if we have already git server then, then their are two solution available,

  1. Make git server to support http protocol
  2. Replicate git server on Redmine server it self

both above option are very easy but issue in second option. Issue if you have git server which is runnning separately. Which happens in my case.

Our git server is only accessisble via git protocol like

git clone user_name@repository_server:path_to_project.git

Our git server is used by more than 30 developers were more than 13 repositories get accessed. So I don't want to distrub the development process. So I have decided to replicate git server on redmine.

A. Replicate git server to be used by Redmine

  1. Login to your Redmine server from console
  2. Clone the repository with following command
  # change to your respective user 
 $ su - name_of_user   
  
  # Create a folder to hold your repository
 $ mkdir /any/path/to/create/repo
 
  # change directory
 $ cd /any/path/to/create/repo
 
 # Make a bare clone of the repo
 $ git clone --bare ssh://git@reposerver/usr/local/git_root/foo-project.git
 
  # Switch to repository
 $ cd foo-project.git
 
  # add orignal repository in newly created repository for fetching changes done in orignal repository 
 $ git remote add origin ssh://git@reposerver/usr/local/git_root/foo-project.git
 
  # Above command will feches commit from origanl repo
 $ git fetch origin
 $ git reset --soft refs/remotes/origin/master

  #Make sure bypass the password prompt using ssh config for following command to work from crontab.
 
  # Add the following to your crontab
 */10 * * * * cd /var/local/git_copies/foo-project.git && git fetch origin && git reset --soft refs/remotes/origin/master > /dev/null

Using above command we have setuped a replica of git server on redmine server.

B. Add project repository in Redmine

Go to the redmine, select your project and add repository local path. Goto => setting => repository

C. Fetch commits into redmine

When you first browse the repository, Redmine retrieves the description of all of the existing commits and stores them in the database.
This is done only once per repository but can take a very long time (or even time out) if your repository has hundreds of commits.

To avoid this, you can do it offline.
Run the following rake command on redmine server:

$ ruby script/runner "Repository.fetch_changesets" -e production

All commits will be retrieved in to the Redmine database.

Since Redmdine 0.9.x, you can use following link of your redmine to execute fetch_changesets for a specific project, or all.
http://redmine.example.com/sys/fetch_changesets (=> fetches changesets for all active projects)
http://redmine.example.com/sys/fetch_changesets?id=foo (=> fetches changesets for project foo only)

Now we have sucessfully configured git reposiroty in Redmine.

Now you can use following link for linking revision and commits to issue and vice-varsa.
http://www.redmine.org/projects/redmine/wiki/RedmineTextFormatting

Thursday, November 3, 2011

Passenger tuning for rails application

Guys, it has been a long over due post. I have finished tuning passenger long back but caught up with Diwali celebration.

Anyways generally I prefer simple and easily understandable configuration. So following configuration is as per my best knowledge and google findings. ;)

I have verified my configuration using ab - Apache HTTP server benchmarking tool. Also tried other tools such as Jmeter, httperf. I have also used passenger-memory-stats for finding rails instance size and passenger-status for finding number of request which are pending in global queue.

I have started passenger tuning using passenger nginx user guide. You will also find passenger-apache guide.

As I am using nginx, following configuration is with respect to nginx but same will applies for apache except some extra directives and syntax.

After digging into passenger tuning, I realized that passenger well configured for production. But still Based on nginx-passenger user guide I have collected following list of directive, which we can configure according to our needs.

Directive Default Value Nginx Block Use
passenger_max_pool_size <integer> 6 http Maximum instances on server
passenger_pool_idle_time <integer> 300 sec http instance idle time
passenger_max_instances_per_app <integer> 0 http Maximum instances allowed to single app
passenger_min_instances <integer> 1 http, server, location, if minimum number of application instances which are always active
passenger_pre_start <url> - http Pre start application
passenger_use_global_queue <on|off> on http, server, location, if Turns the use of global queuing on or off
passenger_ignore_client_abort <on|off> off http, server, location, if Ignore client aborts
rails_framework_spawner_idle_time <integer> 1800 sec http, server, location, if FrameworkSpawner server idle time
rails_app_spawner_idle_time <integer> 600 sec http, server, location, if ApplicationSpawner server idle time
passenger_log_level <integer> 0 (Can be 0, 1, 2, 3) http for how much information Passenger should write into error.log
passenger_debug_log_file <filename> error.log http allow to specify the file that debugging and error messages should be written
passenger_pass_header <header name>
http, server, location, if Used to pass headers

Almost all of these directive has default value which is good enough for an applications. But there are some directive which very important to configure depending on our application environment.

1. passenger_max_pool_size :
            The maximum number of Ruby on Rails or Rack application instances that may be simultaneously active. A larger number results in higher memory usage, but improved ability to handle concurrent HTTP clients.
            The value should be at least equal to the number of CPUs (or CPU cores) that you have. If your system has 2 GB of RAM, then we recommend a value of 30. If your system is a Virtual Private Server (VPS) and has about 256 MB RAM, and is also running other services such as MySQL, then we recommend a value of 2.
            I recomond you to find your application instance size using passenger-memory-stats and configure value of passenger_max_pool_size.
            e.g.  If your application instance size is 300 MB and RAM size 2 GB then value of passenger_max_pool_size should be 4 because 1200 MB(4*300) will be used by application instance and remaning for other process.

2. passenger_max_instances_per_app :
            The maximum number of application instances that may be simultaneously active for a single application. This helps to make sure that a single application will not occupy all available slots in the application pool.
            This value must be less than passenger_max_pool_size. A value of 0 means that there is no limit placed on the number of instances a single application may use, i.e. only the global limit of passenger_max_pool_size will be enforced.

3. passenger_pre_start :
            By default, Phusion Passenger does not start any application instances until said web application is first accessed. The result is that the first visitor of said web application might experience a small delay as Phusion Passenger is starting the web application on demand. If that is undesirable, then this directive can be used to pre-started application instances during Nginx startup.
            This directive accepts the URL of the web application you want to pre-start. It may be specified any number of times.
passenger_pre_start http://foo.com/; 
passenger_pre_start http://bar.com:3500/; 
passenger_pre_start http://myblog.com/store;

Let's get into live scenarios


1. A server with multiple rails applications (Development and test server)
            I have a server with 16 GB of RAM and 8 core cpu, on which redmine(bug tracking system), test rails app and other developers app instances are running. Means you can say mutiple apps are running.
            According to passenger-memory-stats redmine is taking 300 MB and other rails app 500 MB. So I have kept following configuration
passenger_max_pool_size 16;
# arround 8 GB for rails application and remaning for other process
passenger_pool_idle_time 150;
# reduced idle time as multiple app are running
passenger_max_instances_per_app 8; 
# since single app should not use whole pool size, but simuteniouly should handle mutiple requests
2. A server with single rails application (Production server)
            On my production enviroment we have 8 GB of RAM and 4 core cpu, on which only single rails application is running.
            As my rails application instance size is 500 MB, I have kept following configuration on production
passenger_max_pool_size 10;
# arround 5 GB for rails application and remaning for other process
passenger_pool_idle_time 600;
# Increased as it is production
passenger_min_instances 2;
# atlease two instances should in memory at any time
passenger_pre_start http://myprodapp.com/;
# pre start my instance at the time of nginx start instade on first request
For testing whether required instances are forked or not use ab (Apache benchmark) as described above.

Reference : http://www.alfajango.com/blog/performance-tuning-for-phusion-passenger-an-introduction/