Uninitialized constant ActionController:: Metal ::Testing

rails
ruby

#1

‘bundle exec rails test’ fails with the error "uninitialized constant ActionController::metal::Testing " during startup.

I have tried to reproduce this locally with MacOS and Ubuntu. Error only occurs on CircleCI, started occuring a few weeks ago only sometimes, but is now happening each time.

I have tried upgrading Ruby 2.3.3 to 2.4.1.
I have tried upgrading Rails 5.1.2 to 5.1.3RC1.
I have tried switching from CircleCI 1.0 to CircleCI 2.0
Also updated all the gems.
Moved from PhantomJS to Headless Chrome (but tests don’t even get that far, error occurs when loading the first test)

In all configurations, the same effect: Always works locally, always fails in CircleCI.

My best guess it is a timing issue when running tests for the very first time (but ‘spring stop’ did not reproduce the error locally).

The full backtrace is

#!/bin/bash -eo pipefail
bundle exec rails test
/home/circleci/project/vendor/bundle/ruby/2.4.0/gems/actionpack-5.1.3.rc3/lib/action_controller/test_case.rb:12:in `<class:Metal>': uninitialized constant ActionController::Metal::Testing (NameError)
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/actionpack-5.1.3.rc3/lib/action_controller/test_case.rb:11:in `<module:ActionController>'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/actionpack-5.1.3.rc3/lib/action_controller/test_case.rb:10:in `<top (required)>'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/minitest-rails-3.0.0/lib/minitest/rails.rb:55:in `require'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/minitest-rails-3.0.0/lib/minitest/rails.rb:55:in `<top (required)>'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/minitest-rails-capybara-3.0.1/lib/minitest/rails/capybara.rb:1:in `require'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/minitest-rails-capybara-3.0.1/lib/minitest/rails/capybara.rb:1:in `<top (required)>'
	from /home/circleci/project/test/test_helper.rb:1:in `require'
	from /home/circleci/project/test/test_helper.rb:1:in `<top (required)>'
	from /home/circleci/project/test/controllers/area_rules_controller_test.rb:1:in `require'
	from /home/circleci/project/test/controllers/area_rules_controller_test.rb:1:in `<top (required)>'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/test_unit/runner.rb:50:in `require'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/test_unit/runner.rb:50:in `block in load_tests'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/test_unit/runner.rb:50:in `each'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/test_unit/runner.rb:50:in `load_tests'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/test_unit/runner.rb:39:in `run'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/commands/test/test_command.rb:38:in `perform'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/thor-0.19.4/lib/thor/command.rb:27:in `run'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/command/base.rb:63:in `perform'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/command.rb:44:in `invoke'
	from /home/circleci/project/vendor/bundle/ruby/2.4.0/gems/railties-5.1.3.rc3/lib/rails/commands.rb:16:in `<top (required)>'
	from bin/rails:9:in `require'
	from bin/rails:9:in `<main>'
Exited with code 1

#3

The error was triggered by following code snippet in test_helper.rb.
Not sure why this only occured in CircleCI envornment. However,
the optimization (re-using the database connection across tests) is
not needed anymore, and removing it fixed the CircleCI build.

    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.
    ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

#4