Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7662

Show
Ignore:
Timestamp:
09/28/07 14:05:03 (2 years ago)
Author:
david
Message:

Added fixture caching thatll speed up a normal fixture-powered test suite between 50% and 100% (closes #9682) [frederick.cheung@gmail.com]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r7588 r7662  
    11*SVN* 
     2 
     3* Added fixture caching that'll speed up a normal fixture-powered test suite between 50% and 100% #9682 [frederick.cheung@gmail.com] 
    24 
    35* Correctly quote id list for limited eager loading.  #7482 [tmacedo] 
  • trunk/activerecord/lib/active_record/fixtures.rb

    r7584 r7662  
    219219  DEFAULT_FILTER_RE = /\.ya?ml$/ 
    220220 
     221  @@all_cached_fixtures = {} 
     222   
     223  def self.reset_cache(connection=ActiveRecord::Base.connection) 
     224    @@all_cached_fixtures[connection.object_id] = {} 
     225  end 
     226   
     227  def self.cache_for_connection(connection) 
     228    @@all_cached_fixtures[connection.object_id] ||= {} 
     229    @@all_cached_fixtures[connection.object_id] 
     230  end 
     231   
     232  def self.fixture_is_cached?(connection, table_name) 
     233    cache_for_connection(connection)[table_name] 
     234  end 
     235 
     236  def self.cached_fixtures(connection, keys_to_fetch = nil) 
     237    if keys_to_fetch 
     238      fixtures = cache_for_connection(connection).values_at(*keys_to_fetch) 
     239    else 
     240      fixtures = cache_for_connection(connection).values 
     241    end 
     242    fixtures.size > 1 ? fixtures : fixtures.first 
     243  end 
     244 
     245  def self.cache_fixtures(connection, fixtures) 
     246    cache_for_connection(connection).merge! fixtures.index_by(&:table_name) 
     247  end 
     248   
    221249  def self.instantiate_fixtures(object, table_name, fixtures, load_instances=true) 
    222250    object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures 
     
    247275    connection  = block_given? ? yield : ActiveRecord::Base.connection 
    248276 
    249     ActiveRecord::Base.silence do 
    250       fixtures_map = {} 
    251  
    252       fixtures = table_names.map do |table_name| 
    253         fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s)) 
    254       end                
    255  
    256       all_loaded_fixtures.merge! fixtures_map   
    257  
    258       connection.transaction(Thread.current['open_transactions'].to_i == 0) do 
    259         fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures } 
    260         fixtures.each { |fixture| fixture.insert_fixtures } 
    261  
    262         # Cap primary key sequences to max(pk). 
    263         if connection.respond_to?(:reset_pk_sequence!) 
    264           table_names.each do |table_name| 
    265             connection.reset_pk_sequence!(table_name) 
    266           end 
    267         end 
    268       end 
    269  
    270       return fixtures.size > 1 ? fixtures : fixtures.first 
    271     end 
     277    table_names_to_fetch = table_names.reject {|table_name| fixture_is_cached?(connection, table_name)} 
     278     
     279    unless table_names_to_fetch.empty? 
     280      ActiveRecord::Base.silence do 
     281        fixtures_map = {} 
     282 
     283        fixtures = table_names_to_fetch.map do |table_name| 
     284          fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s)) 
     285        end                
     286 
     287        all_loaded_fixtures.merge! fixtures_map   
     288 
     289        connection.transaction(Thread.current['open_transactions'].to_i == 0) do 
     290          fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures } 
     291          fixtures.each { |fixture| fixture.insert_fixtures } 
     292 
     293          # Cap primary key sequences to max(pk). 
     294          if connection.respond_to?(:reset_pk_sequence!) 
     295            table_names.each do |table_name| 
     296              connection.reset_pk_sequence!(table_name) 
     297            end 
     298          end 
     299        end 
     300         
     301        cache_fixtures(connection, fixtures) 
     302      end 
     303    end 
     304    return cached_fixtures(connection, table_names) 
    272305  end 
    273306 
     
    548581        @fixture_cache = Hash.new 
    549582 
     583        if !use_transactional_fixtures? 
     584          Fixtures.reset_cache #we don't want the test to use any of our cached data 
     585        end 
     586         
    550587        # Load fixtures once and begin transaction. 
    551588        if use_transactional_fixtures? 
     
    574611        return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank? 
    575612 
     613        if !use_transactional_fixtures? 
     614          Fixtures.reset_cache #the non transactional test may have fiddled with the data - dump caches 
     615        end 
     616         
    576617        # Rollback changes if a transaction is active. 
    577618        if use_transactional_fixtures? && Thread.current['open_transactions'] != 0 
  • trunk/activerecord/test/connection_test_mysql.rb

    r6838 r7662  
    22 
    33class MysqlConnectionTest < Test::Unit::TestCase 
     4  self.use_transactional_fixtures = false 
    45  def setup 
    56    @connection = ActiveRecord::Base.connection 
  • trunk/activerecord/test/fixtures_test.rb

    r6940 r7662  
    5959  if ActiveRecord::Base.connection.supports_migrations? 
    6060    def test_inserts_with_pre_and_suffix 
     61      Fixtures.reset_cache 
    6162      ActiveRecord::Base.connection.create_table :prefix_topics_suffix do |t| 
    6263        t.column :title, :string 
     
    426427  end 
    427428end 
     429 
     430class FasterFixturesTest < Test::Unit::TestCase 
     431  fixtures :categories, :authors 
     432   
     433  def run(*args, &block) 
     434    Fixtures.reset_cache 
     435    super(*args, &block) 
     436  end 
     437   
     438  def load_extra_fixture(name) 
     439    fixture = create_fixtures(name) 
     440    assert fixture.is_a?(Fixtures) 
     441    @loaded_fixtures[fixture.table_name] = fixture 
     442  end 
     443   
     444  def test_cache 
     445    assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'categories') 
     446    assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'authors') 
     447     
     448    assert_no_queries do 
     449      create_fixtures('categories') 
     450      create_fixtures('authors') 
     451    end 
     452     
     453    load_extra_fixture('posts') 
     454    assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'posts') 
     455    self.class.setup_fixture_accessors('posts') 
     456    assert_equal 'Welcome to the weblog', posts(:welcome).title 
     457  end 
     458end