The Depot Application

The Depot Application

15 Rails In Depth 14.4 Integration Testing of Applications

14.5 Performance Testing

mkdir test/fixtures/performance/
edit test/fixtures/performance/products.yml
<% 1.upto(1000) do |i| %>
product_<%= i %>:
  id: <%= i %>
  title: Product Number <%= i %>
  description: My description
  image_url: product.gif
  price: 1234
<% end %>
edit test/performance/order_speed_test.rb
require 'test_helper'
require 'store_controller'
 
class OrderSpeedTest < ActionController::TestCase
  tests StoreController
  
  DAVES_DETAILS = {
      :name     => "Dave Thomas",
      :address  => "123 The Street",
      :email    => "dave@example.com",
      :pay_type => "check"
  }
  
  self.fixture_path = File.join(File.dirname(__FILE__), "../fixtures/performance")
  fixtures :products
  
 
  def test_100_orders
    Order.delete_all
    LineItem.delete_all
 
    @controller.logger.silence do
      elapsed_time = Benchmark.realtime do
        100.downto(1) do |prd_id|
          cart = Cart.new
          cart.add_product(Product.find(prd_id))
          post :save_order, 
               { :order => DAVES_DETAILS },
               { :cart  => cart }
          assert_redirected_to :action => :index
        end         
      end       
      assert_equal 100, Order.count
      assert elapsed_time < 3.00
    end
  end
end
ruby -I test test/performance/order_speed_test.rb
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/gem_dependency.rb:21.
NOTE: Gem::SourceIndex#initialize is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#initialize called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/vendor_gem_source_index.rb:100.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
Loaded suite test/performance/order_speed_test
Started
.
Finished in 2.391871 seconds.
 
1 tests, 102 assertions, 0 failures, 0 errors
edit app/models/user.rb
require 'digest/sha1'
 
class User < ActiveRecord::Base
  
  validates_presence_of     :name
  validates_uniqueness_of   :name
 
  attr_accessor :password_confirmation
  validates_confirmation_of :password
 
  validate :password_non_blank
  
  def self.authenticate(name, password)
    user = self.find_by_name(name)
    if user
      expected_password = encrypted_password(password, user.salt)
      if user.hashed_password != expected_password
        user = nil
      end
    end
    user
  end
  
  # 'password' is a virtual attribute
  def password
    @password
  end
  
  def password=(pwd)
    @password = pwd
    return if pwd.blank?
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end
  
  after_destroy :ensure_an_admin_remains
 
  def ensure_an_admin_remains
    if User.count.zero?
      raise "Can't delete last user"
    end
  end     
 
private
 
  def password_non_blank
    errors.add(:password, "Missing password") if hashed_password.blank?
  end
  
  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end
  
  def self.encrypted_password(password, salt)
    100000.times { Math.sin(1)}
    string_to_hash = password + "wibble" + salt
    Digest::SHA1.hexdigest(string_to_hash)
  end
end
ruby script/performance/benchmarker "User.encrypted_password(\"secret\", \"salt\")"
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/gem_dependency.rb:21.
NOTE: Gem::SourceIndex#initialize is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#initialize called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/vendor_gem_source_index.rb:100.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
            user     system      total        real
#1      0.190000   0.000000   0.190000 (  0.186192)
ruby script/performance/profiler "User.encrypted_password(\"secret\", \"salt\")"
NOTE: Gem.source_index is deprecated, use Specification. It will be removed on or after 2011-11-01.
Gem.source_index called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/gem_dependency.rb:21.
NOTE: Gem::SourceIndex#initialize is deprecated with no replacement. It will be removed on or after 2011-11-01.
Gem::SourceIndex#initialize called from /home/rubys/git/awdwr/edition3/work-23/depot/config/../vendor/rails/railties/lib/rails/vendor_gem_source_index.rb:100.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
NOTE: Gem::SourceIndex#add_spec is deprecated, use Specification.add_spec. It will be removed on or after 2011-11-01.
Gem::SourceIndex#add_spec called from /home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91.
Loading Rails...
Using the standard Ruby profiler.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 67.17     3.97      3.97        1  3970.00  5700.00  Integer#times
 29.27     5.70      1.73   100000     0.02     0.02  Math.sin
  2.37     5.84      0.14        4    35.00    37.50  Array#select
  0.68     5.88      0.04        5     8.00    10.00  Array#map
  0.17     5.89      0.01      777     0.01     0.01  Hash#key?
  0.17     5.90      0.01      785     0.01     0.01  String#to_s
  0.17     5.91      0.01        3     3.33     3.33  Kernel.send
  0.00     5.91      0.00        2     0.00     0.00  String#size
  0.00     5.91      0.00        2     0.00     0.00  Kernel.==
  0.00     5.91      0.00        2     0.00     0.00  Array#-
  0.00     5.91      0.00        6     0.00     0.00  String#[]
  0.00     5.91      0.00        3     0.00     0.00  Hash#each
  0.00     5.91      0.00        1     0.00     0.00  Digest::Class#digest
  0.00     5.91      0.00        1     0.00     0.00  Digest::Base#finish
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoloaded_constants
  0.00     5.91      0.00        6     0.00     0.00  Hash#default
  0.00     5.91      0.00        3     0.00     0.00  Module#===
  0.00     5.91      0.00       14     0.00     0.00  Module#const_defined?
  0.00     5.91      0.00        6     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoload_paths
  0.00     5.91      0.00       11     0.00     0.00  File#expand_path
  0.00     5.91      0.00        1     0.00     0.00  String#ends_with?
  0.00     5.91      0.00        5     0.00     0.00  ActiveSupport::Dependencies.log_call
  0.00     5.91      0.00        9     0.00     0.00  Module#blank_slate_method_added
  0.00     5.91      0.00       12     0.00     0.00  String#split
  0.00     5.91      0.00        9     0.00     0.00  Object#method_added
  0.00     5.91      0.00        6     0.00     0.00  Mutex#synchronize
  0.00     5.91      0.00       24     0.00     0.00  Module#constants
  0.00     5.91      0.00        1     0.00     0.00  TrueClass#duplicable?
  0.00     5.91      0.00       10     0.00     0.00  ActiveSupport::Dependencies.uninherited_const_defined?
  0.00     5.91      0.00       11     0.00     0.00  Array#concat
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.qualified_name_for
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#match
  0.00     5.91      0.00        5     0.00     0.00  Symbol#to_s
  0.00     5.91      0.00        1     0.00    10.00  ActiveRecord::Validations::ClassMethods.validates_presence_of
  0.00     5.91      0.00        5     0.00     0.00  ActiveSupport::Callbacks::CallbackChain#extract_options
  0.00     5.91      0.00        7     0.00     0.00  String#gsub
  0.00     5.91      0.00        7     0.00     0.00  Array#include?
  0.00     5.91      0.00        5     0.00     0.00  Array#empty?
  0.00     5.91      0.00        1     0.00     0.00  Object#initialize
  0.00     5.91      0.00        4     0.00     0.00  ActiveRecord::Base#validate
  0.00     5.91      0.00        5     0.00     0.00  ActiveSupport::Callbacks::CallbackChain#build
  0.00     5.91      0.00        5     0.00     0.00  Array#flatten!
  0.00     5.91      0.00        7     0.00     0.00  String#==
  0.00     5.91      0.00        4     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.constantize
  0.00     5.91      0.00        1     0.00     0.00  Digest::Base#update
  0.00     5.91      0.00        1     0.00     0.00  Array#uniq!
  0.00     5.91      0.00        1     0.00     0.00  Enumerable.any?
  0.00     5.91      0.00        6     0.00     0.00  Module#name
  0.00     5.91      0.00        2     0.00     0.00  Kernel.hash
  0.00     5.91      0.00        1     0.00     0.00  Gem.unresolved_deps
  0.00     5.91      0.00        2     0.00   155.00  ActiveSupport::Dependencies.new_constants_in
  0.00     5.91      0.00        1     0.00     0.00  Array#uniq
  0.00     5.91      0.00       34     0.00     0.00  Module#==
  0.00     5.91      0.00       10     0.00    20.00  Array#collect
  0.00     5.91      0.00        2     0.00     0.00  Symbol#to_sym
  0.00     5.91      0.00       10     0.00     0.00  Fixnum#==
  0.00     5.91      0.00        4     0.00     0.00  String#blank?
  0.00     5.91      0.00        1     0.00     0.00  Kernel.gem_original_require
  0.00     5.91      0.00       18     0.00     0.00  Kernel.object_id
  0.00     5.91      0.00        1     0.00     0.00  String#downcase
  0.00     5.91      0.00        2     0.00     0.00  Array#initialize_copy
  0.00     5.91      0.00        2     0.00     0.00  Digest::Base#reset
  0.00     5.91      0.00        1     0.00   210.00  ActiveSupport::Dependencies.load_file
  0.00     5.91      0.00        3     0.00     0.00  String#+
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Base#inherited
  0.00     5.91      0.00        2     0.00     0.00  Kernel.instance_variable_set
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Observing::ClassMethods.inherited
  0.00     5.91      0.00        2     0.00     0.00  Array#delete_if
  0.00     5.91      0.00        3     0.00     0.00  ActiveSupport::Dependencies.loaded
  0.00     5.91      0.00        1     0.00     0.00  Digest::Instance.digest
  0.00     5.91      0.00        1     0.00     0.00  Module#private
  0.00     5.91      0.00        8     0.00     0.00  Regexp#escape
  0.00     5.91      0.00        1     0.00     0.00  Kernel.require
  0.00     5.91      0.00        3     0.00     0.00  Array#*
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.warnings_on_first_load
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.history
  0.00     5.91      0.00       11     0.00     0.00  Enumerable.inject
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.search_for_file
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#match
  0.00     5.91      0.00       12     0.00     0.00  Array#first
  0.00     5.91      0.00       10     0.00     0.00  Array#last
  0.00     5.91      0.00        9     0.00     0.00  ActiveSupport::Dependencies.log_activity
  0.00     5.91      0.00        2     0.00     0.00  Set#<<
  0.00     5.91      0.00        3     0.00     0.00  File#file?
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.autoload_once_paths
  0.00     5.91      0.00        1     0.00     0.00  Array#compact
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::Dependencies.mechanism
  0.00     5.91      0.00        8     0.00     0.00  ActiveSupport::Dependencies.qualified_const_defined?
  0.00     5.91      0.00        4     0.00    37.50  ActiveSupport::CoreExtensions::Module.local_constants
  0.00     5.91      0.00        2     0.00     0.00  Module#attr_accessor
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.camelize
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.loadable_constants_for_path
  0.00     5.91      0.00        2     0.00     0.00  Hash#include?
  0.00     5.91      0.00        2     0.00     0.00  Kernel.singleton_method_added
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Base#after_destroy
  0.00     5.91      0.00        1     0.00     0.00  Exception#initialize
  0.00     5.91      0.00        1     0.00     0.00  Observable.changed
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.to_constant_name
  0.00     5.91      0.00        3     0.00     0.00  File#join
  0.00     5.91      0.00        7     0.00     0.00  Array#initialize
  0.00     5.91      0.00        5     0.00     0.00  Kernel.block_given?
  0.00     5.91      0.00        5     0.00     0.00  Array#flatten
  0.00     5.91      0.00       12     0.00     0.00  String#empty?
  0.00     5.91      0.00        2     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_each
  0.00     5.91      0.00        2     0.00     0.00  Kernel.equal?
  0.00     5.91      0.00        2     0.00     0.00  Array#blank?
  0.00     5.91      0.00        3     0.00     0.00  Class#inheritable_attributes
  0.00     5.91      0.00        5     0.00     0.00  Array#pop
  0.00     5.91      0.00        4     0.00     0.00  ActiveSupport::Dependencies.log
  0.00     5.91      0.00        4     0.00     0.00  Regexp#===
  0.00     5.91      0.00       14     0.00     0.00  Hash#[]
  0.00     5.91      0.00        7     0.00     0.00  Hash#update
  0.00     5.91      0.00        3     0.00     0.00  String#upcase
  0.00     5.91      0.00        2     0.00     0.00  Kernel.respond_to?
  0.00     5.91      0.00        1     0.00     0.00  NilClass#nil?
  0.00     5.91      0.00        1     0.00     0.00  NameError#initialize
  0.00     5.91      0.00        1     0.00     0.00  String#tr
  0.00     5.91      0.00        1     0.00   110.00  Kernel.load_without_new_constant_marking
  0.00     5.91      0.00       40     0.00     0.00  Array#each
  0.00     5.91      0.00        5     0.00     0.00  ActiveSupport::Callbacks::Callback#initialize
  0.00     5.91      0.00        4     0.00     0.00  ActiveSupport::Inflector.constantize
  0.00     5.91      0.00        2     0.00     0.00  Class#inherited
  0.00     5.91      0.00        1     0.00     0.00  Hash#initialize_copy
  0.00     5.91      0.00        3     0.00     0.00  Object#duplicable?
  0.00     5.91      0.00        1     0.00   210.00  ActiveSupport::Dependencies.load_missing_constant
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Base#respond_to?
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#initialize
  0.00     5.91      0.00        1     0.00     0.00  Observable.notify_observers
  0.00     5.91      0.00        1     0.00  5910.00  Object#profile_me
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_confirmation_of
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::CoreExtensions::Hash::Keys.symbolize_keys
  0.00     5.91      0.00        6     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack_mutex
  0.00     5.91      0.00        1     0.00   100.00  ActiveSupport::Dependencies::Loadable.require
  0.00     5.91      0.00        1     0.00     0.00  Hash#empty?
  0.00     5.91      0.00        3     0.00     0.00  ActiveRecord::Validations::ClassMethods.validation_method
  0.00     5.91      0.00        1     0.00   210.00  ActiveSupport::Dependencies::ModuleConstMissing.const_missing
  0.00     5.91      0.00        1     0.00   210.00  ActiveSupport::Dependencies.require_or_load
  0.00     5.91      0.00        4     0.00     0.00  Module#ancestors
  0.00     5.91      0.00       21     0.00     0.00  Module#const_get
  0.00     5.91      0.00        3     0.00     0.00  Kernel.dup
  0.00     5.91      0.00        5     0.00     0.00  Symbol#===
  0.00     5.91      0.00       10     0.00     0.00  ActiveSupport::CoreExtensions::Array::ExtractOptions.extract_options!
  0.00     5.91      0.00        9     0.00     0.00  ActiveSupport::Dependencies.logger
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load_once_path?
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::Inflector.underscore
  0.00     5.91      0.00        1     0.00  5700.00  User#encrypted_password
  0.00     5.91      0.00        1     0.00     0.00  Digest::Class#hexdigest
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::Dependencies.load?
  0.00     5.91      0.00       19     0.00     0.00  Kernel.is_a?
  0.00     5.91      0.00        1     0.00   210.00  ActiveSupport::Dependencies::ClassConstMissing.const_missing
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_uniqueness_of
  0.00     5.91      0.00        5     0.00     0.00  Array#map!
  0.00     5.91      0.00        2     0.00     0.00  Set#include?
  0.00     5.91      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#initialize
  0.00     5.91      0.00       12     0.00     0.00  Hash#[]=
  0.00     5.91      0.00        2     0.00     0.00  ActiveSupport::Inflector.camelize
  0.00     5.91      0.00        4     0.00     0.00  Array#<<
  0.00     5.91      0.00        4     0.00    50.00  ActiveSupport::CoreExtensions::Module.local_constant_names
  0.00     5.91      0.00       15     0.00     0.00  Class#new
  0.00     5.91      0.00        1     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.underscore
  0.00     5.91      0.00        1     0.00  5910.00  #toplevel
edit app/models/user.rb

15 Rails In Depth 14.4 Integration Testing of Applications