Why not use shared ActiveRecord connections for Rspec + Selenium?

后端 未结 6 1838
傲寒
傲寒 2020-11-30 23:12

It seems the most commonly accepted way to deal with Selenium and tests is to avoid using transactional fixtures and then using something like database_cleaner between tests

相关标签:
6条回答
  • 2020-11-30 23:21

    There's a good thing at the end of this post. It may explain why I get a MALLOC error when I attempt to a very simple threading script.

    http://apidock.com/rails/ActiveRecord/Base/connection

    leente - March 15, 2011 0 thanks
    Don't cache it!
    
    Don’t store a connection in a variable, because another thread might try to use it when it’s already checked back in into the connection pool. See: ActiveRecord::ConnectionAdapters::ConnectionPool
    
    connection = ActiveRecord::Base.connection
    
    threads = (1..100).map do
      Thread.new do
        begin
          10.times do
            connection.execute("SELECT SLEEP(1)")  # WRONG
            ActiveRecord::Base.connection.execute("SELECT SLEEP(1)")  # CORRECT
          end
          puts "success"
        rescue => e
          puts e.message
        end
      end
    end
    
    threads.each(&:join)
    
    0 讨论(0)
  • 2020-11-30 23:22

    I was just doing a little reading on this myself. I discovered the snippet you shared here in this blog post:

    http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/

    To answer your question directly, the database cleaner github page cautions that it can " result in non-deterministic failures". I'd go right ahead and use it, but if you start running into weird failures, maybe this is a good place to start looking.

    0 讨论(0)
  • 2020-11-30 23:24

    I have encountered a problem using the code you mentioned in my spec_helper.rb file.

    What happens when your tests depend on using connections to multiple databases? I have two databases I need to connect to when I run my tests. I did a simple test to check what was happening to the database connections I establish.

    class ActiveRecord::Base
       mattr_accessor :shared_connection
       @@shared_connection = nil
    
       def self.connection
         @@shared_connection || retrieve_connection
      end
    end
    
    # Forces all threads to share the same connection. This works on
    # Capybara because it starts the web server in a thread.
    puts "First Record cxn: #{FirstDatabase::Record.connection}"
    # => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xe59b524>
    puts "AR Base cxn: #{ActiveRecord::Base.connection}"
    # => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
    ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
    
    puts "First Record cxn: #{FirstDatabase::Record.connection}"
    # => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
    puts "AR Base cxn: #{ActiveRecord::Base.connection}"
    # => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
    

    As you can see, before I call the shared connection method, I have two different database connections. After, the shared connection method call, I have only one.

    So any test that requires going to the second database connection to retrieve information will fail. :(

    I'm going to post this problem and see if anyone has arrived at a solution.

    0 讨论(0)
  • 2020-11-30 23:28

    This solution was written by Jose Valim - well respected in the Rails community and a member of the Rails core team. I doubt he would recommend using it if there were issues with it. I personally haven't had any issues.

    Just be aware that if you use Spork this needs to be in the each_run block to work.

    FWIW - I have had intermittent capybara test issues with the above patch on Postgres. The Mike Perham solution that @hsgubert has below appears to have solved those issues. I am now use that solution.

    0 讨论(0)
  • 2020-11-30 23:41

    Actually there are issues with it. If you use the gem mysql2, for example, you'll start seeing some errors like:

    Mysql2::Error This connection is still waiting for a result
    

    Please use this instead. It was written by Mike Perham, all credits to him.

    class ActiveRecord::Base
      mattr_accessor :shared_connection
      @@shared_connection = nil
    
      def self.connection
        @@shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
      end
    end
    
    ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
    

    You'll need to install gem connection_pool too. This will spare you from many headaches.

    0 讨论(0)
  • 2020-11-30 23:42

    The DatabaseCleaner gem readme answers your "why not" question this way:

    One common approach is to force all processes to use the same database connection (common ActiveRecord hack) however this approach has been reported to result in non-deterministic failures.

    0 讨论(0)
提交回复
热议问题