Remove legacy_connection_handling

This functionality has been deprecated since Rails 6.1 and can now be
removed. I've deleted all code, docs, references, and tests related to
this feature.
This commit is contained in:
eileencodes 2022-04-01 15:15:32 -04:00
parent ca6d15ba17
commit ad52c0a197
No known key found for this signature in database
GPG Key ID: BA5C575120BBE8DF
28 changed files with 58 additions and 2276 deletions

View File

@ -1,3 +1,7 @@
* Remove `ActiveRecord.legacy_connection_handling`.
*Eileen M. Uchitelle*
* `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple

View File

@ -178,9 +178,6 @@ module ActiveRecord
singleton_class.attr_accessor :schema_cache_ignored_tables
self.schema_cache_ignored_tables = []
singleton_class.attr_accessor :legacy_connection_handling
self.legacy_connection_handling = true
singleton_class.attr_reader :default_timezone
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling

View File

@ -11,7 +11,6 @@ module ActiveRecord
autoload :Column
autoload :PoolConfig
autoload :PoolManager
autoload :LegacyPoolManager
autoload :SchemaCache
autoload :Deduplicable

View File

@ -88,28 +88,6 @@ module ActiveRecord
ActiveSupport::IsolatedExecutionState[:active_record_prevent_writes] = prevent_writes
end
# Prevent writing to the database regardless of role.
#
# In some cases you may want to prevent writes to the database
# even if you are on a database that can write. +while_preventing_writes+
# will prevent writes to the database for the duration of the block.
#
# This method does not provide the same protection as a readonly
# user and is meant to be a safeguard against accidental writes.
#
# See +READ_QUERY+ for the queries that are blocked by this
# method.
def while_preventing_writes(enabled = true)
unless ActiveRecord.legacy_connection_handling
raise NotImplementedError, "`while_preventing_writes` is only available on the connection_handler with legacy_connection_handling"
end
original, self.prevent_writes = self.prevent_writes, enabled
yield
ensure
self.prevent_writes = original
end
def connection_pool_names # :nodoc:
owner_to_pool_manager.keys
end
@ -143,11 +121,7 @@ module ActiveRecord
payload[:config] = db_config.configuration_hash
end
if ActiveRecord.legacy_connection_handling
owner_to_pool_manager[pool_config.connection_specification_name] ||= LegacyPoolManager.new
else
owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
end
owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
pool_manager = get_pool_manager(pool_config.connection_specification_name)
pool_manager.set_pool_config(role, shard, pool_config)

View File

@ -151,16 +151,10 @@ module ActiveRecord
# Determines whether writes are currently being prevented.
#
# Returns true if the connection is a replica.
#
# If the application is using legacy handling, returns
# true if +connection_handler.prevent_writes+ is set.
#
# If the application is using the new connection handling
# will return true based on +current_preventing_writes+.
# Returns true if the connection is a replica or returns
# the value of +current_preventing_writes+.
def preventing_writes?
return true if replica?
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
return false if connection_class.nil?
connection_class.current_preventing_writes

View File

@ -1,35 +0,0 @@
# frozen_string_literal: true
module ActiveRecord
module ConnectionAdapters
class LegacyPoolManager # :nodoc:
def initialize
@name_to_pool_config = {}
end
def shard_names
@name_to_pool_config.keys
end
def pool_configs(_ = nil)
@name_to_pool_config.values
end
def remove_pool_config(_, shard)
@name_to_pool_config.delete(shard)
end
def get_pool_config(_, shard)
@name_to_pool_config[shard]
end
def set_pool_config(role, shard, pool_config)
if pool_config
@name_to_pool_config[shard] = pool_config
else
raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
end
end
end
end
end

View File

@ -135,18 +135,12 @@ module ActiveRecord
# Dog.first # finds first Dog record stored on the shard one replica
# end
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
if ActiveRecord.legacy_connection_handling
if self != Base
raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
end
else
if self != Base && !abstract_class
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
end
if self != Base && !abstract_class
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
end
if name != connection_specification_name && !primary_class?
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
end
if name != connection_specification_name && !primary_class?
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
end
unless role || shard
@ -172,10 +166,6 @@ module ActiveRecord
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
classes = classes.flatten
if ActiveRecord.legacy_connection_handling
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
end
if self != Base || classes.include?(Base)
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
end
@ -196,10 +186,6 @@ module ActiveRecord
# It is not recommended to use this method in a request since it
# does not yield to a block like +connected_to+.
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
if ActiveRecord.legacy_connection_handling
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
end
prevent_writes = true if role == ActiveRecord.reading_role
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
@ -236,11 +222,7 @@ module ActiveRecord
# See +READ_QUERY+ for the queries that are blocked by this
# method.
def while_preventing_writes(enabled = true, &block)
if ActiveRecord.legacy_connection_handling
connection_handler.while_preventing_writes(enabled, &block)
else
connected_to(role: current_role, prevent_writes: enabled, &block)
end
connected_to(role: current_role, prevent_writes: enabled, &block)
end
# Returns true if role is the current connected role.
@ -254,23 +236,12 @@ module ActiveRecord
end
def lookup_connection_handler(handler_key) # :nodoc:
if ActiveRecord.legacy_connection_handling
handler_key ||= ActiveRecord.writing_role
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
else
ActiveRecord::Base.connection_handler
end
ActiveRecord::Base.connection_handler
end
# Clears the query cache for all connections associated with the current thread.
def clear_query_caches_for_current_thread
if ActiveRecord.legacy_connection_handling
ActiveRecord::Base.connection_handlers.each_value do |handler|
clear_on_handler(handler)
end
else
clear_on_handler(ActiveRecord::Base.connection_handler)
end
clear_on_handler(ActiveRecord::Base.connection_handler)
end
# Returns the connection currently associated with the class. This can
@ -362,19 +333,10 @@ module ActiveRecord
def with_role_and_shard(role, shard, prevent_writes)
prevent_writes = true if role == ActiveRecord.reading_role
if ActiveRecord.legacy_connection_handling
with_handler(role.to_sym) do
connection_handler.while_preventing_writes(prevent_writes) do
append_to_connected_to_stack(shard: shard, klasses: [self])
yield
end
end
else
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
return_value = yield
return_value.load if return_value.is_a? ActiveRecord::Relation
return_value
end
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
return_value = yield
return_value.load if return_value.is_a? ActiveRecord::Relation
return_value
ensure
self.connected_to_stack.pop
end

View File

@ -109,33 +109,6 @@ module ActiveRecord
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
end
def self.connection_handlers
if ActiveRecord.legacy_connection_handling
else
raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
end
@@connection_handlers ||= {}
end
def self.connection_handlers=(handlers)
if ActiveRecord.legacy_connection_handling
ActiveSupport::Deprecation.warn(<<~MSG)
Using legacy connection handling is deprecated. Please set
`legacy_connection_handling` to `false` in your application.
The new connection handling does not support `connection_handlers`
getter and setter.
Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
MSG
else
raise NotImplementedError, "The new connection handling does not support multiple connection handlers."
end
@@connection_handlers = handlers
end
def self.asynchronous_queries_session # :nodoc:
asynchronous_queries_tracker.current_session
end
@ -155,16 +128,12 @@ module ActiveRecord
# ActiveRecord::Base.current_role #=> :reading
# end
def self.current_role
if ActiveRecord.legacy_connection_handling
connection_handlers.key(connection_handler) || default_role
else
connected_to_stack.reverse_each do |hash|
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
end
default_role
connected_to_stack.reverse_each do |hash|
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
end
default_role
end
# Returns the symbol representing the current connected shard.
@ -196,16 +165,12 @@ module ActiveRecord
# ActiveRecord::Base.current_preventing_writes #=> false
# end
def self.current_preventing_writes
if ActiveRecord.legacy_connection_handling
connection_handler.prevent_writes
else
connected_to_stack.reverse_each do |hash|
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
end
false
connected_to_stack.reverse_each do |hash|
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
end
false
end
def self.connected_to_stack # :nodoc:
@ -325,7 +290,7 @@ module ActiveRecord
end
%w(
reading_role writing_role legacy_connection_handling default_timezone index_nested_attribute_errors
reading_role writing_role default_timezone index_nested_attribute_errors
verbose_query_logs queues warn_on_records_fetched_greater_than maintain_test_schema
application_record_class action_on_strict_loading_violation schema_format error_on_ignored_order
timestamped_migrations dump_schema_after_migration dump_schemas suppress_multiple_database_warning

View File

@ -27,31 +27,15 @@ module ActiveRecord
def self.run
pools = []
if ActiveRecord.legacy_connection_handling
ActiveRecord::Base.connection_handlers.each do |key, handler|
pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
end
else
pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
end
pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
pools
end
def self.complete(pools)
pools.each { |pool| pool.disable_query_cache! }
if ActiveRecord.legacy_connection_handling
ActiveRecord::Base.connection_handlers.each do |_, handler|
handler.connection_pool_list.each do |pool|
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
end
end
else
ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
end
ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
end
end

View File

@ -270,9 +270,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
# and then establishes the connection.
initializer "active_record.initialize_database" do
ActiveSupport.on_load(:active_record) do
if ActiveRecord.legacy_connection_handling
self.connection_handlers = { ActiveRecord.writing_role => ActiveRecord::Base.default_connection_handler }
end
self.configurations = Rails.application.config.database_configuration
establish_connection

View File

@ -92,7 +92,6 @@ module ActiveRecord
@fixture_connections = []
@@already_loaded_fixtures ||= {}
@connection_subscriber = nil
@legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
# Load fixtures once and begin transaction.
@ -174,74 +173,38 @@ module ActiveRecord
# need to share a connection pool so that the reading connection
# can see data in the open transaction on the writing connection.
def setup_shared_connection_pool
if ActiveRecord.legacy_connection_handling
writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord.writing_role]
handler = ActiveRecord::Base.connection_handler
ActiveRecord::Base.connection_handlers.values.each do |handler|
if handler != writing_handler
handler.connection_pool_names.each do |name|
writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
return unless writing_pool_manager
handler.connection_pool_names.each do |name|
pool_manager = handler.send(:owner_to_pool_manager)[name]
pool_manager.shard_names.each do |shard_name|
writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
@saved_pool_configs[name][shard_name] ||= {}
pool_manager.role_names.each do |role|
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
next if pool_config == writing_pool_config
pool_manager = handler.send(:owner_to_pool_manager)[name]
@legacy_saved_pool_configs[handler][name] ||= {}
pool_manager.shard_names.each do |shard_name|
writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
pool_config = pool_manager.get_pool_config(nil, shard_name)
next if pool_config == writing_pool_config
@legacy_saved_pool_configs[handler][name][shard_name] = pool_config
pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
end
end
end
end
else
handler = ActiveRecord::Base.connection_handler
handler.connection_pool_names.each do |name|
pool_manager = handler.send(:owner_to_pool_manager)[name]
pool_manager.shard_names.each do |shard_name|
writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
@saved_pool_configs[name][shard_name] ||= {}
pool_manager.role_names.each do |role|
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
next if pool_config == writing_pool_config
@saved_pool_configs[name][shard_name][role] = pool_config
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
end
@saved_pool_configs[name][shard_name][role] = pool_config
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
end
end
end
end
def teardown_shared_connection_pool
if ActiveRecord.legacy_connection_handling
@legacy_saved_pool_configs.each_pair do |handler, names|
names.each_pair do |name, shards|
shards.each_pair do |shard_name, pool_config|
pool_manager = handler.send(:owner_to_pool_manager)[name]
pool_manager.set_pool_config(nil, shard_name, pool_config)
end
end
end
else
handler = ActiveRecord::Base.connection_handler
handler = ActiveRecord::Base.connection_handler
@saved_pool_configs.each_pair do |name, shards|
pool_manager = handler.send(:owner_to_pool_manager)[name]
shards.each_pair do |shard_name, roles|
roles.each_pair do |role, pool_config|
next unless pool_manager.get_pool_config(role, shard_name)
@saved_pool_configs.each_pair do |name, shards|
pool_manager = handler.send(:owner_to_pool_manager)[name]
shards.each_pair do |shard_name, roles|
roles.each_pair do |role, pool_config|
next unless pool_manager.get_pool_config(role, shard_name)
pool_manager.set_pool_config(role, shard_name, pool_config)
end
pool_manager.set_pool_config(role, shard_name, pool_config)
end
end
end
@legacy_saved_pool_configs.clear
@saved_pool_configs.clear
end

View File

@ -143,130 +143,4 @@ module ActiveRecord
end
end
end
class AdapterPreventWritesLegacyTest < ActiveRecord::TestCase
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
@connection = ActiveRecord::Base.connection
@connection_handler = ActiveRecord::Base.connection_handler
end
def teardown
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = @old_value
end
def test_preventing_writes_predicate_legacy
assert_not_predicate @connection, :preventing_writes?
@connection_handler.while_preventing_writes do
assert_predicate @connection, :preventing_writes?
end
assert_not_predicate @connection, :preventing_writes?
end
def test_errors_when_an_insert_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
end
end
def test_errors_when_an_update_query_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.update("UPDATE subscribers SET nick = '9989' WHERE nick = '138853948594'")
end
end
end
def test_errors_when_a_delete_query_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.delete("DELETE FROM subscribers WHERE nick = '138853948594'")
end
end
end
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
result = @connection.select_all("SELECT subscribers.* FROM subscribers WHERE nick = '138853948594'")
assert_equal 1, result.length
end
end
if ActiveRecord::Base.connection.supports_common_table_expressions?
def test_doesnt_error_when_a_read_query_with_a_cte_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
result = @connection.select_all(<<~SQL)
WITH matching_subscribers AS (SELECT subscribers.* FROM subscribers WHERE nick = '138853948594')
SELECT * FROM matching_subscribers
SQL
assert_equal 1, result.length
end
end
end
def test_doesnt_error_when_a_select_query_starting_with_a_slash_star_comment_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
result = @connection.select_all("/* some comment */ SELECT subscribers.* FROM subscribers WHERE nick = '138853948594'")
assert_equal 1, result.length
end
end
def test_errors_when_an_insert_query_prefixed_by_a_slash_star_comment_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.insert("/* some comment */ INSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
end
end
def test_doesnt_error_when_a_select_query_starting_with_double_dash_comments_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
result = @connection.select_all("-- some comment\n-- comment about INSERT\nSELECT subscribers.* FROM subscribers WHERE nick = '138853948594'")
assert_equal 1, result.length
end
end
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.insert("-- some comment\nINSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
end
end
def test_errors_when_an_insert_query_prefixed_by_a_slash_star_comment_containing_read_command_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.insert("/* SELECT */ INSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
end
end
def test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_containing_read_command_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.insert("-- SELECT\nINSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
end
end
end
end

View File

@ -100,109 +100,3 @@ class Mysql2AdapterPreventWritesTest < ActiveRecord::Mysql2TestCase
super(@conn, "ex", definition, &block)
end
end
class Mysql2AdapterPreventWritesLegacyTest < ActiveRecord::Mysql2TestCase
include DdlHelper
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
@conn = ActiveRecord::Base.connection
@connection_handler = ActiveRecord::Base.connection_handler
end
def teardown
ActiveRecord.legacy_connection_handling = @old_value
end
def test_errors_when_an_insert_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
end
end
end
def test_errors_when_an_update_query_is_called_while_preventing_writes
@conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.update("UPDATE `engines` SET `engines`.`car_id` = '9989' WHERE `engines`.`car_id` = '138853948594'")
end
end
end
def test_errors_when_a_delete_query_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("DELETE FROM `engines` where `engines`.`car_id` = '138853948594'")
end
end
end
def test_errors_when_a_replace_query_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("REPLACE INTO `engines` SET `engines`.`car_id` = '249823948'")
end
end
end
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594'").entries.count
end
end
def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_equal 2, @conn.execute("SHOW FULL FIELDS FROM `engines`").entries.count
end
end
def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_nil @conn.execute("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci")
end
end
def test_doesnt_error_when_a_describe_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_equal 2, @conn.execute("DESCRIBE engines").entries.count
end
end
def test_doesnt_error_when_a_desc_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_equal 2, @conn.execute("DESC engines").entries.count
end
end
def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("/*action:index*/(\n( SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594' ) )").entries.count
end
end
def test_doesnt_error_when_a_use_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
db_name = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary").database
assert_nil @conn.execute("USE #{db_name}")
end
end
private
def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block)
super(@conn, "ex", definition, &block)
end
end

View File

@ -99,107 +99,5 @@ module ActiveRecord
super(@connection, "ex", definition, &block)
end
end
class PostgreSQLAdapterPreventWritesLegacyTest < ActiveRecord::PostgreSQLTestCase
self.use_transactional_tests = false
include DdlHelper
include ConnectionHelper
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
@connection = ActiveRecord::Base.connection
@connection_handler = ActiveRecord::Base.connection_handler
end
def teardown
ActiveRecord.legacy_connection_handling = @old_value
end
def test_errors_when_an_insert_query_is_called_while_preventing_writes
with_example_table do
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
end
end
end
end
def test_errors_when_an_update_query_is_called_while_preventing_writes
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'")
end
end
end
end
def test_errors_when_a_delete_query_is_called_while_preventing_writes
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@connection.execute("DELETE FROM ex where data = '138853948594'")
end
end
end
end
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("SELECT * FROM ex WHERE data = '138853948594'").entries.count
end
end
end
def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("SHOW TIME ZONE").entries.count
end
end
def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes
@connection_handler.while_preventing_writes do
assert_equal [], @connection.execute("SET standard_conforming_strings = on").entries
end
end
def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preventing_writes
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("/*action:index*/(\n( SELECT * FROM ex WHERE data = '138853948594' ) )").entries.count
end
end
end
def test_doesnt_error_when_a_read_query_with_cursors_is_called_while_preventing_writes
with_example_table do
@connection_handler.while_preventing_writes do
@connection.transaction do
assert_equal [], @connection.execute("DECLARE cur_ex CURSOR FOR SELECT * FROM ex").entries
assert_equal [], @connection.execute("FETCH cur_ex").entries
assert_equal [], @connection.execute("MOVE cur_ex").entries
assert_equal [], @connection.execute("CLOSE cur_ex").entries
end
end
end
end
private
def with_example_table(definition = "id serial primary key, number integer, data character varying(255)", &block)
super(@connection, "ex", definition, &block)
end
end
end
end

View File

@ -89,98 +89,5 @@ module ActiveRecord
super(@conn, table_name, definition, &block)
end
end
class SQLite3AdapterPreventWritesLegacyTest < ActiveRecord::SQLite3TestCase
include DdlHelper
self.use_transactional_tests = false
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
@conn = ActiveRecord::Base.connection
@connection_handler = ActiveRecord::Base.connection_handler
end
def teardown
ActiveRecord.legacy_connection_handling = @old_value
end
def test_errors_when_an_insert_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
end
end
end
end
def test_errors_when_an_update_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'")
end
end
end
end
def test_errors_when_a_delete_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("DELETE FROM ex where data = '138853948594'")
end
end
end
end
def test_errors_when_a_replace_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_raises(ActiveRecord::ReadOnlyError) do
@conn.execute("REPLACE INTO ex (data) VALUES ('249823948')")
end
end
end
end
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("SELECT data from ex WHERE data = '138853948594'").count
end
end
end
def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preventing_writes
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
@connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("/*action:index*/ SELECT data from ex WHERE data = '138853948594'").count
end
end
end
private
def with_example_table(definition = nil, table_name = "ex", &block)
definition ||= <<~SQL
id integer PRIMARY KEY AUTOINCREMENT,
number integer
SQL
super(@conn, table_name, definition, &block)
end
end
end
end

View File

@ -93,136 +93,4 @@ class BasePreventWritesTest < ActiveRecord::TestCase
end
end
end
class BasePreventWritesLegacyTest < ActiveRecord::TestCase
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
ActiveRecord::Base.establish_connection :arunit
ARUnit2Model.establish_connection :arunit2
end
def teardown
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = @old_value
end
if !in_memory_db?
test "creating a record raises if preventing writes" do
ActiveRecord::Base.connection_handler.while_preventing_writes do
error = assert_raises ActiveRecord::ReadOnlyError do
Bird.create! name: "Bluejay"
end
assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, error.message
end
end
test "updating a record raises if preventing writes" do
bird = Bird.create! name: "Bluejay"
ActiveRecord::Base.connection_handler.while_preventing_writes do
error = assert_raises ActiveRecord::ReadOnlyError do
bird.update! name: "Robin"
end
assert_match %r/\AWrite query attempted while in readonly mode: UPDATE /, error.message
end
end
test "deleting a record raises if preventing writes" do
bird = Bird.create! name: "Bluejay"
ActiveRecord::Base.connection_handler.while_preventing_writes do
error = assert_raises ActiveRecord::ReadOnlyError do
bird.destroy!
end
assert_match %r/\AWrite query attempted while in readonly mode: DELETE /, error.message
end
end
test "selecting a record does not raise if preventing writes" do
bird = Bird.create! name: "Bluejay"
ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_equal bird, Bird.where(name: "Bluejay").last
end
end
test "an explain query does not raise if preventing writes" do
Bird.create!(name: "Bluejay")
ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_queries(2) { Bird.where(name: "Bluejay").explain }
end
end
test "an empty transaction does not raise if preventing writes" do
ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_queries(2, ignore_none: true) do
Bird.transaction do
ActiveRecord::Base.connection.materialize_transactions
end
end
end
end
test "preventing writes applies to all connections on a handler" do
ActiveRecord::Base.connection_handler.while_preventing_writes do
conn1_error = assert_raises ActiveRecord::ReadOnlyError do
assert_equal ActiveRecord::Base.connection, Bird.connection
assert_not_equal ARUnit2Model.connection, Bird.connection
Bird.create!(name: "Bluejay")
end
assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message
end
ActiveRecord::Base.connection_handler.while_preventing_writes do
conn2_error = assert_raises ActiveRecord::ReadOnlyError do
assert_not_equal ActiveRecord::Base.connection, Professor.connection
assert_equal ARUnit2Model.connection, Professor.connection
Professor.create!(name: "Professor Bluejay")
end
assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message
end
end
test "preventing writes with multiple handlers" do
ActiveRecord::Base.connects_to(database: { writing: :arunit, reading: :arunit })
ActiveRecord::Base.connected_to(role: :writing) do
conn1_error = assert_raises ActiveRecord::ReadOnlyError do
assert_equal :writing, ActiveRecord::Base.current_role
ActiveRecord::Base.connection_handler.while_preventing_writes do
Bird.create!(name: "Bluejay")
end
end
assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message
end
ActiveRecord::Base.connected_to(role: :reading) do
conn2_error = assert_raises ActiveRecord::ReadOnlyError do
assert_equal :reading, ActiveRecord::Base.current_role
ActiveRecord::Base.connection_handler.while_preventing_writes do
Bird.create!(name: "Bluejay")
end
end
assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message
end
end
test "current_preventing_writes" do
ActiveRecord::Base.connection_handler.while_preventing_writes do
assert ActiveRecord::Base.current_preventing_writes, "expected connection current_preventing_writes to return true"
end
end
end
end
end

View File

@ -1665,20 +1665,6 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "`connects_to` can only be called on ActiveRecord::Base or abstract classes", error.message
end
test "cannot call connected_to on subclasses of ActiveRecord::Base with legacy connection handling" do
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
error = assert_raises(NotImplementedError) do
Bird.connected_to(role: :reading) { }
end
assert_equal "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling.", error.message
ensure
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = old_value
end
test "cannot call connected_to with role and shard on non-abstract classes" do
error = assert_raises(NotImplementedError) do
Bird.connected_to(role: :reading, shard: :default) { }
@ -1727,28 +1713,6 @@ class BasicsTest < ActiveRecord::TestCase
ActiveRecord::Base.connected_to_stack.pop
end
test "#connecting_to doesn't work with legacy connection handling" do
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_raises NotImplementedError do
SecondAbstractClass.connecting_to(role: :writing, prevent_writes: true)
end
ensure
ActiveRecord.legacy_connection_handling = old_value
end
test "#connected_to_many doesn't work with legacy connection handling" do
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_raises NotImplementedError do
ActiveRecord::Base.connected_to_many([SecondAbstractClass], role: :writing)
end
ensure
ActiveRecord.legacy_connection_handling = old_value
end
test "#connected_to_many cannot be called on anything but ActiveRecord::Base" do
assert_raises NotImplementedError do
SecondAbstractClass.connected_to_many([SecondAbstractClass], role: :writing)

View File

@ -1,479 +0,0 @@
# frozen_string_literal: true
require "cases/helper"
require "models/person"
module ActiveRecord
module ConnectionAdapters
class LegacyConnectionHandlersMultiDbTest < ActiveRecord::TestCase
self.use_transactional_tests = false
fixtures :people
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_deprecated do
ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
end
@handlers = { writing: ConnectionHandler.new, reading: ConnectionHandler.new }
@rw_handler = @handlers[:writing]
@ro_handler = @handlers[:reading]
@owner_name = "ActiveRecord::Base"
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
@rw_pool = @handlers[:writing].establish_connection(db_config)
@ro_pool = @handlers[:reading].establish_connection(db_config)
end
def teardown
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = @old_value
end
class SecondaryBase < ActiveRecord::Base
self.abstract_class = true
end
class MultiConnectionTestModel < SecondaryBase
end
def test_multiple_connection_handlers_works_in_a_threaded_environment
tf_writing = Tempfile.open "test_writing"
tf_reading = Tempfile.open "test_reading"
# We need to use a role for reading not named reading, otherwise we'll prevent writes
# and won't be able to write to the second connection.
SecondaryBase.connects_to database: { writing: { database: tf_writing.path, adapter: "sqlite3" }, secondary: { database: tf_reading.path, adapter: "sqlite3" } }
ActiveRecord::Base.connected_to(role: :writing) do
MultiConnectionTestModel.connection.execute("CREATE TABLE `multi_connection_test_models` (connection_role VARCHAR (255))")
MultiConnectionTestModel.connection.execute("INSERT INTO multi_connection_test_models VALUES ('writing')")
end
ActiveRecord::Base.connected_to(role: :secondary) do
MultiConnectionTestModel.connection.execute("CREATE TABLE `multi_connection_test_models` (connection_role VARCHAR (255))")
MultiConnectionTestModel.connection.execute("INSERT INTO multi_connection_test_models VALUES ('reading')")
end
read_latch = Concurrent::CountDownLatch.new
write_latch = Concurrent::CountDownLatch.new
MultiConnectionTestModel.connection
thread = Thread.new do
MultiConnectionTestModel.connection
write_latch.wait
assert_equal "writing", MultiConnectionTestModel.connection.select_value("SELECT connection_role from multi_connection_test_models")
read_latch.count_down
end
ActiveRecord::Base.connected_to(role: :secondary) do
write_latch.count_down
assert_equal "reading", MultiConnectionTestModel.connection.select_value("SELECT connection_role from multi_connection_test_models")
read_latch.wait
end
thread.join
ensure
tf_reading.close
tf_reading.unlink
tf_writing.close
tf_writing.unlink
end
def test_loading_relations_with_multi_db_connection_handlers
# We need to use a role for reading not named reading, otherwise we'll prevent writes
# and won't be able to write to the second connection.
SecondaryBase.connects_to database: { writing: { database: ":memory:", adapter: "sqlite3" }, secondary: { database: ":memory:", adapter: "sqlite3" } }
relation = ActiveRecord::Base.connected_to(role: :secondary) do
MultiConnectionTestModel.connection.execute("CREATE TABLE `multi_connection_test_models` (connection_role VARCHAR (255))")
MultiConnectionTestModel.create!(connection_role: "reading")
MultiConnectionTestModel.where(connection_role: "reading")
end
assert_equal "reading", relation.first.connection_role
end
unless in_memory_db?
def test_not_setting_writing_role_while_using_another_named_role_raises
old_handler = ActiveRecord::Base.connection_handler
assert_deprecated do
ActiveRecord::Base.connection_handlers = { writing: ConnectionHandler.new }
end
ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handlers[:writing]
ActiveRecord::Base.establish_connection :arunit
ActiveRecord::Base.connects_to(shards: { default: { all: :arunit }, one: { all: :arunit } })
assert_raises(ArgumentError) { setup_shared_connection_pool }
ensure
ActiveRecord::Base.connection_handler = old_handler
ActiveRecord::Base.establish_connection :arunit
end
def test_setting_writing_role_while_using_another_named_role_does_not_raise
old_role, ActiveRecord.writing_role = ActiveRecord.writing_role, :all
old_handler = ActiveRecord::Base.connection_handler
assert_deprecated do
ActiveRecord::Base.connection_handlers = { all: ConnectionHandler.new }
end
ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handlers[:all]
ActiveRecord::Base.establish_connection :arunit
ActiveRecord::Base.connects_to(shards: { default: { all: :arunit }, one: { all: :arunit } })
assert_nothing_raised { setup_shared_connection_pool }
ensure
ActiveRecord.writing_role = old_role
ActiveRecord::Base.connection_handler = old_handler
ActiveRecord::Base.establish_connection :arunit
end
def test_establish_connection_using_3_levels_config
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"readonly" => { "adapter" => "sqlite3", "database" => "test/db/readonly.sqlite3", "replica" => true },
"default" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(database: { writing: :default, reading: :readonly })
@pool = ActiveRecord::Base.connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base")
assert_not_nil @pool
assert_equal "test/db/primary.sqlite3", @pool.db_config.database
assert_equal "default", @pool.db_config.name
@pool2 = ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base")
assert_not_nil @pool2
assert_equal "test/db/readonly.sqlite3", @pool2.db_config.database
assert_equal "readonly", @pool2.db_config.name
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_switching_connections_via_handler
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"readonly" => { "adapter" => "sqlite3", "database" => "test/db/readonly.sqlite3" },
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(database: { writing: :primary, reading: :readonly })
ActiveRecord::Base.connected_to(role: :reading) do
@ro_handler = ActiveRecord::Base.connection_handler
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:reading]
assert_equal :reading, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :reading)
assert_not ActiveRecord::Base.connected_to?(role: :writing)
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ActiveRecord::Base.connected_to(role: :writing) do
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_equal @ro_handler, ActiveRecord::Base.connection_handler
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
assert_not ActiveRecord::Base.connected_to?(role: :reading)
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_establish_connection_using_3_levels_config_with_non_default_handlers
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"readonly" => { "adapter" => "sqlite3", "database" => "test/db/readonly.sqlite3" },
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(database: { default: :primary, readonly: :readonly })
@pool = ActiveRecord::Base.connection_handlers[:default].retrieve_connection_pool("ActiveRecord::Base")
assert_not_nil @pool
assert_equal "test/db/primary.sqlite3", @pool.db_config.database
@pool2 = ActiveRecord::Base.connection_handlers[:readonly].retrieve_connection_pool("ActiveRecord::Base")
assert_not_nil @pool2
assert_equal "test/db/readonly.sqlite3", @pool2.db_config.database
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_switching_connections_with_database_url
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
previous_url, ENV["DATABASE_URL"] = ENV["DATABASE_URL"], "postgres://localhost/foo"
ActiveRecord::Base.connects_to(database: { writing: "postgres://localhost/bar" })
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
handler = ActiveRecord::Base.connection_handler
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_nil pool = handler.retrieve_connection_pool("ActiveRecord::Base")
assert_equal({ adapter: "postgresql", database: "bar", host: "localhost" }, pool.db_config.configuration_hash)
ensure
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
ENV["DATABASE_URL"] = previous_url
end
def test_switching_connections_with_database_config_hash
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = { adapter: "sqlite3", database: "test/db/readonly.sqlite3" }
ActiveRecord::Base.connects_to(database: { writing: config })
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
handler = ActiveRecord::Base.connection_handler
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_nil pool = handler.retrieve_connection_pool("ActiveRecord::Base")
assert_equal(config, pool.db_config.configuration_hash)
ensure
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_switching_connections_without_database_and_role_raises
error = assert_raises(ArgumentError) do
ActiveRecord::Base.connected_to { }
end
assert_equal "must provide a `shard` and/or `role`.", error.message
end
def test_switching_connections_with_database_symbol_uses_default_role
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"animals" => { adapter: "sqlite3", database: "test/db/animals.sqlite3" },
"primary" => { adapter: "sqlite3", database: "test/db/primary.sqlite3" }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(database: { writing: :animals })
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
handler = ActiveRecord::Base.connection_handler
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_nil pool = handler.retrieve_connection_pool("ActiveRecord::Base")
assert_equal(config["default_env"]["animals"], pool.db_config.configuration_hash)
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_switching_connections_with_database_hash_uses_passed_role_and_database
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"animals" => { adapter: "sqlite3", database: "test/db/animals.sqlite3" },
"primary" => { adapter: "sqlite3", database: "test/db/primary.sqlite3" }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(database: { writing: :primary })
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
handler = ActiveRecord::Base.connection_handler
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_nil pool = handler.retrieve_connection_pool("ActiveRecord::Base")
assert_equal(config["default_env"]["primary"], pool.db_config.configuration_hash)
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_connects_to_with_single_configuration
config = {
"development" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to database: { writing: :development }
assert_equal 1, ActiveRecord::Base.connection_handlers.size
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:writing]
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing)
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
end
def test_connects_to_using_top_level_key_in_two_level_config
config = {
"development" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"development_readonly" => { "adapter" => "sqlite3", "database" => "test/db/readonly.sqlite3" }
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to database: { writing: :development, reading: :development_readonly }
@pool = ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base")
assert_not_nil @pool
assert_equal "test/db/readonly.sqlite3", @pool.db_config.database
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
end
def test_connects_to_returns_array_of_established_connections
config = {
"development" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"development_readonly" => { "adapter" => "sqlite3", "database" => "test/db/readonly.sqlite3" }
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
result = ActiveRecord::Base.connects_to database: { writing: :development, reading: :development_readonly }
assert_equal(
[
ActiveRecord::Base.connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base"),
ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base")
],
result
)
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
end
end
def test_connection_pools
assert_equal([@rw_pool], @handlers[:writing].connection_pools)
assert_equal([@ro_pool], @handlers[:reading].connection_pools)
end
def test_retrieve_connection
assert @rw_handler.retrieve_connection(@owner_name)
assert @ro_handler.retrieve_connection(@owner_name)
end
def test_active_connections?
assert_not_predicate @rw_handler, :active_connections?
assert_not_predicate @ro_handler, :active_connections?
assert @rw_handler.retrieve_connection(@owner_name)
assert @ro_handler.retrieve_connection(@owner_name)
assert_predicate @rw_handler, :active_connections?
assert_predicate @ro_handler, :active_connections?
@rw_handler.clear_active_connections!
assert_not_predicate @rw_handler, :active_connections?
@ro_handler.clear_active_connections!
assert_not_predicate @ro_handler, :active_connections?
end
def test_retrieve_connection_pool
assert_not_nil @rw_handler.retrieve_connection_pool(@owner_name)
assert_not_nil @ro_handler.retrieve_connection_pool(@owner_name)
end
def test_retrieve_connection_pool_with_invalid_id
assert_nil @rw_handler.retrieve_connection_pool("foo")
assert_nil @ro_handler.retrieve_connection_pool("foo")
end
def test_connection_handlers_are_per_thread_and_not_per_fiber
assert_deprecated do
ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new }
end
reading_handler = ActiveRecord::Base.connection_handlers[:reading]
reading = ActiveRecord::Base.connected_to(role: :reading) do
Person.connection_handler
end
assert_not_equal reading, ActiveRecord::Base.connection_handler
assert_equal reading, reading_handler
end
def test_connection_handlers_swapping_connections_in_fiber
assert_deprecated do
ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new }
end
reading_handler = ActiveRecord::Base.connection_handlers[:reading]
enum = Enumerator.new do |r|
r << ActiveRecord::Base.connection_handler
end
reading = ActiveRecord::Base.connected_to(role: :reading) do
enum.next
end
assert_equal reading, reading_handler
end
def test_calling_connected_to_on_a_non_existent_handler_raises
error = assert_raises ActiveRecord::ConnectionNotEstablished do
ActiveRecord::Base.connected_to(role: :reading) do
Person.first
end
end
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'reading' role.", error.message
end
def test_default_handlers_are_writing_and_reading
assert_equal :writing, ActiveRecord.writing_role
assert_equal :reading, ActiveRecord.reading_role
end
def test_an_application_can_change_the_default_handlers
old_writing = ActiveRecord.writing_role
old_reading = ActiveRecord.reading_role
ActiveRecord.writing_role = :default
ActiveRecord.reading_role = :readonly
assert_equal :default, ActiveRecord.writing_role
assert_equal :readonly, ActiveRecord.reading_role
ensure
ActiveRecord.writing_role = old_writing
ActiveRecord.reading_role = old_reading
end
end
end
end

View File

@ -1,588 +0,0 @@
# frozen_string_literal: true
require "cases/helper"
require "models/person"
module ActiveRecord
module ConnectionAdapters
class LegacyConnectionHandlersShardingDbTest < ActiveRecord::TestCase
self.use_transactional_tests = false
fixtures :people
def setup
@legacy_setting = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_deprecated do
ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
end
@handlers = { writing: ConnectionHandler.new, reading: ConnectionHandler.new }
@rw_handler = @handlers[:writing]
@ro_handler = @handlers[:reading]
@owner_name = "ActiveRecord::Base"
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
@rw_pool = @handlers[:writing].establish_connection(db_config)
@ro_pool = @handlers[:reading].establish_connection(db_config)
end
def teardown
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = @legacy_setting
end
unless in_memory_db?
def test_establishing_a_connection_in_connected_to_block_uses_current_role_and_shard
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
SecondaryBase.establish_connection(db_config)
assert_equal [:shard_one], ActiveRecord::Base.connection_handlers[:writing].send(:owner_to_pool_manager).fetch("ActiveRecord::ConnectionAdapters::LegacyConnectionHandlersShardingDbTest::SecondaryBase").instance_variable_get(:@name_to_pool_config).keys
end
end
def test_establish_connection_using_3_levels_config
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(shards: {
default: { writing: :primary },
shard_one: { writing: :primary_shard_one }
})
connection_handlers = ActiveRecord::Base.connection_handlers
base_pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base")
default_pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base", shard: :default)
assert_equal base_pool, default_pool
assert_equal "test/db/primary.sqlite3", default_pool.db_config.database
assert_equal "primary", default_pool.db_config.name
assert_not_nil pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base", shard: :shard_one)
assert_equal "test/db/primary_shard_one.sqlite3", pool.db_config.database
assert_equal "primary_shard_one", pool.db_config.name
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_establish_connection_using_3_levels_config_with_shards_and_replica
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"primary_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3", "replica" => true },
"primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
"primary_shard_one_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3", "replica" => true }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(shards: {
default: { writing: :primary, reading: :primary_replica },
shard_one: { writing: :primary_shard_one, reading: :primary_shard_one_replica }
})
connection_handlers = ActiveRecord::Base.connection_handlers
default_writing_pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base", shard: :default)
base_writing_pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base")
assert_equal base_writing_pool, default_writing_pool
assert_equal "test/db/primary.sqlite3", default_writing_pool.db_config.database
assert_equal "primary", default_writing_pool.db_config.name
default_reading_pool = connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base", shard: :default)
base_reading_pool = connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base")
assert_equal base_reading_pool, default_reading_pool
assert_equal "test/db/primary.sqlite3", default_reading_pool.db_config.database
assert_equal "primary_replica", default_reading_pool.db_config.name
assert_not_nil pool = connection_handlers[:writing].retrieve_connection_pool("ActiveRecord::Base", shard: :shard_one)
assert_equal "test/db/primary_shard_one.sqlite3", pool.db_config.database
assert_equal "primary_shard_one", pool.db_config.name
assert_not_nil pool = connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base", shard: :shard_one)
assert_equal "test/db/primary_shard_one.sqlite3", pool.db_config.database
assert_equal "primary_shard_one_replica", pool.db_config.name
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_switching_connections_via_handler
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"primary_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3", "replica" => true },
"primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
"primary_shard_one_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3", "replica" => true }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(shards: {
default: { writing: :primary, reading: :primary_replica },
shard_one: { writing: :primary_shard_one, reading: :primary_shard_one_replica }
})
ActiveRecord::Base.connected_to(role: :reading, shard: :default) do
@ro_handler = ActiveRecord::Base.connection_handler
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:reading]
assert_equal :reading, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_equal @ro_handler, ActiveRecord::Base.connection_handler
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
@ro_handler = ActiveRecord::Base.connection_handler
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:reading]
assert_equal :reading, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
assert_equal ActiveRecord::Base.connection_handler, ActiveRecord::Base.connection_handlers[:writing]
assert_not_equal @ro_handler, ActiveRecord::Base.connection_handler
assert_equal :writing, ActiveRecord::Base.current_role
assert ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
end
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_retrieves_proper_connection_with_nested_connected_to
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"primary_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3", "replica" => true },
"primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
"primary_shard_one_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3", "replica" => true }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(shards: {
default: { writing: :primary, reading: :primary_replica },
shard_one: { writing: :primary_shard_one, reading: :primary_shard_one_replica }
})
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
# Uses the correct connection
assert_equal "primary_shard_one_replica", ActiveRecord::Base.connection_pool.db_config.name
# Uses the shard currently in use
ActiveRecord::Base.connected_to(role: :writing) do
assert_equal "primary_shard_one", ActiveRecord::Base.connection_pool.db_config.name
end
# Allows overriding the shard as well
ActiveRecord::Base.connected_to(role: :reading, shard: :default) do
assert_equal "primary_replica", ActiveRecord::Base.connection_pool.db_config.name
end
# Resets correctly
assert_equal "primary_shard_one_replica", ActiveRecord::Base.connection_pool.db_config.name
end
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
def test_connected_to_raises_without_a_shard_or_role
error = assert_raises(ArgumentError) do
ActiveRecord::Base.connected_to { }
end
assert_equal "must provide a `shard` and/or `role`.", error.message
end
def test_connects_to_raises_with_a_shard_and_database_key
error = assert_raises(ArgumentError) do
ActiveRecord::Base.connects_to(database: { writing: :arunit }, shards: { shard_one: { writing: :arunit } })
end
assert_equal "`connects_to` can only accept a `database` or `shards` argument, but not both arguments.", error.message
end
def test_retrieve_connection_pool_with_invalid_shard
assert_not_nil @rw_handler.retrieve_connection_pool("ActiveRecord::Base")
assert_nil @rw_handler.retrieve_connection_pool("ActiveRecord::Base", shard: :foo)
assert_not_nil @ro_handler.retrieve_connection_pool("ActiveRecord::Base")
assert_nil @ro_handler.retrieve_connection_pool("ActiveRecord::Base", shard: :foo)
end
def test_calling_connected_to_on_a_non_existent_shard_raises
ActiveRecord::Base.connects_to(shards: {
default: { writing: :arunit, reading: :arunit }
})
error = assert_raises ActiveRecord::ConnectionNotEstablished do
ActiveRecord::Base.connected_to(role: :reading, shard: :foo) do
Person.first
end
end
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'foo' shard.", error.message
end
def test_retrieves_proper_connection_with_nested_connected_to_on_abstract_classes
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = {
"default_env" => {
"primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
"primary_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3", "replica" => true },
"primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
"primary_shard_one_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3", "replica" => true },
"primary_shard_two" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_two.sqlite3" },
"primary_shard_two_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_two.sqlite3", "replica" => true },
"secondary" => { "adapter" => "sqlite3", "database" => "test/db/secondary.sqlite3" },
"secondary_replica" => { "adapter" => "sqlite3", "database" => "test/db/secondary.sqlite3", "replica" => true },
"secondary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/secondary_shard_one.sqlite3" },
"secondary_shard_one_replica" => { "adapter" => "sqlite3", "database" => "test/db/secondary_shard_one.sqlite3", "replica" => true },
"secondary_shard_two" => { "adapter" => "sqlite3", "database" => "test/db/secondary_shard_two.sqlite3" },
"secondary_shard_two_replica" => { "adapter" => "sqlite3", "database" => "test/db/secondary_shard_two.sqlite3", "replica" => true }
}
}
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
ActiveRecord::Base.connects_to(shards: {
default: { writing: :primary, reading: :primary_replica },
shard_one: { writing: :primary_shard_one, reading: :primary_shard_one_replica }
})
SecondaryBase.connects_to(shards: {
default: { writing: :secondary, reading: :secondary_replica },
shard_one: { writing: :secondary_shard_one, reading: :secondary_shard_one_replica },
shard_two: { writing: :secondary_shard_two, reading: :secondary_shard_two_replica }
})
assert_equal "primary", ActiveRecord::Base.connection_pool.db_config.name
assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
# ActiveRecord:Base is a global switch for passed values
assert_equal "primary_shard_one_replica", ActiveRecord::Base.connection_pool.db_config.name
assert_equal "secondary_shard_one_replica", SecondaryBase.connection_pool.db_config.name
ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
assert_equal "primary", ActiveRecord::Base.connection_pool.db_config.name
assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_two) do
# ActiveRecord::Base has no shard_two
assert_equal "secondary_shard_two_replica", SecondaryBase.connection_pool.db_config.name
end
ActiveRecord::Base.connected_to(role: :writing) do
assert_equal "primary", ActiveRecord::Base.connection_pool.db_config.name
assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
end
end
end
assert_equal "primary", ActiveRecord::Base.connection_pool.db_config.name
assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
ensure
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env
end
end
class SecondaryBase < ActiveRecord::Base
self.abstract_class = true
end
class ShardConnectionTestModel < SecondaryBase
end
class SomeOtherBase < ActiveRecord::Base
self.abstract_class = true
end
class ShardConnectionTestModelB < SomeOtherBase
end
def test_same_shards_across_clusters
SecondaryBase.connects_to shards: { one: { writing: { database: ":memory:", adapter: "sqlite3" } } }
SomeOtherBase.connects_to shards: { one: { writing: { database: ":memory:", adapter: "sqlite3" } } }
ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.create!(shard_key: "test_model_default")
ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_model_bs` (shard_key VARCHAR (255))")
ShardConnectionTestModelB.create!(shard_key: "test_model_b_default")
assert_equal "test_model_default", ShardConnectionTestModel.where(shard_key: "test_model_default").first.shard_key
assert_equal "test_model_b_default", ShardConnectionTestModelB.where(shard_key: "test_model_b_default").first.shard_key
end
end
def test_sharding_separation
SecondaryBase.connects_to shards: {
default: { writing: { database: ":memory:", adapter: "sqlite3" } },
one: { writing: { database: ":memory:", adapter: "sqlite3" } }
}
[:default, :one].each do |shard_name|
ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
end
end
ActiveRecord::Base.connected_to(role: :writing) do
# Create a record on :default
ShardConnectionTestModel.create!(shard_key: "foo")
end
# Make sure we can read it when explicitly connecting to :default
ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
assert ShardConnectionTestModel.find_by_shard_key("foo")
end
# Switch to shard and make sure we can't read the record from :default
# Also add a new record on :one
ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
assert_not ShardConnectionTestModel.find_by_shard_key("foo")
ShardConnectionTestModel.create!(shard_key: "bar")
end
# Make sure we can't read the record from :one but can read the record
# from :default
assert_not ShardConnectionTestModel.find_by_shard_key("bar")
assert ShardConnectionTestModel.find_by_shard_key("foo")
end
def test_swapping_shards_globally_in_a_multi_threaded_environment
tf_default = Tempfile.open "shard_key_default"
tf_shard_one = Tempfile.open "shard_key_one"
SecondaryBase.connects_to shards: {
default: { writing: { database: tf_default.path, adapter: "sqlite3" } },
one: { writing: { database: tf_shard_one.path, adapter: "sqlite3" } }
}
[:default, :one].each do |shard_name|
ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
end
end
shard_one_latch = Concurrent::CountDownLatch.new
shard_default_latch = Concurrent::CountDownLatch.new
ActiveRecord::Base.connected_to(role: :writing) do
ShardConnectionTestModel.connection
end
thread = Thread.new do
ActiveRecord::Base.connected_to(role: :writing) do
ShardConnectionTestModel.connection
shard_default_latch.wait
assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
shard_one_latch.count_down
end
end
ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
shard_default_latch.count_down
assert_equal "shard_key_one", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
shard_one_latch.wait
end
thread.join
ensure
tf_shard_one.close
tf_shard_one.unlink
tf_default.close
tf_default.unlink
end
def test_swapping_shards_and_roles_in_a_multi_threaded_environment
tf_default = Tempfile.open "shard_key_default"
tf_shard_one = Tempfile.open "shard_key_one"
tf_default_reading = Tempfile.open "shard_key_default_reading"
tf_shard_one_reading = Tempfile.open "shard_key_one_reading"
SecondaryBase.connects_to shards: {
default: { writing: { database: tf_default.path, adapter: "sqlite3" }, secondary: { database: tf_default_reading.path, adapter: "sqlite3" } },
one: { writing: { database: tf_shard_one.path, adapter: "sqlite3" }, secondary: { database: tf_shard_one_reading.path, adapter: "sqlite3" } }
}
[:default, :one].each do |shard_name|
ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
end
ActiveRecord::Base.connected_to(role: :secondary, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
end
end
shard_one_latch = Concurrent::CountDownLatch.new
shard_default_latch = Concurrent::CountDownLatch.new
ShardConnectionTestModel.connection
thread = Thread.new do
ShardConnectionTestModel.connection
shard_default_latch.wait
assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
shard_one_latch.count_down
end
ActiveRecord::Base.connected_to(shard: :one, role: :secondary) do
shard_default_latch.count_down
assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
shard_one_latch.wait
end
thread.join
ensure
tf_shard_one.close
tf_shard_one.unlink
tf_default.close
tf_default.unlink
tf_shard_one_reading.close
tf_shard_one_reading.unlink
tf_default_reading.close
tf_default_reading.unlink
end
def test_swapping_granular_shards_and_roles_in_a_multi_threaded_environment
tf_default = Tempfile.open "shard_key_default"
tf_shard_one = Tempfile.open "shard_key_one"
tf_default_reading = Tempfile.open "shard_key_default_reading"
tf_shard_one_reading = Tempfile.open "shard_key_one_reading"
tf_default2 = Tempfile.open "shard_key_default2"
tf_shard_one2 = Tempfile.open "shard_key_one2"
tf_default_reading2 = Tempfile.open "shard_key_default_reading2"
tf_shard_one_reading2 = Tempfile.open "shard_key_one_reading2"
SecondaryBase.connects_to shards: {
default: { writing: { database: tf_default.path, adapter: "sqlite3" }, secondary: { database: tf_default_reading.path, adapter: "sqlite3" } },
one: { writing: { database: tf_shard_one.path, adapter: "sqlite3" }, secondary: { database: tf_shard_one_reading.path, adapter: "sqlite3" } }
}
SomeOtherBase.connects_to shards: {
default: { writing: { database: tf_default2.path, adapter: "sqlite3" }, secondary: { database: tf_default_reading2.path, adapter: "sqlite3" } },
one: { writing: { database: tf_shard_one2.path, adapter: "sqlite3" }, secondary: { database: tf_shard_one_reading2.path, adapter: "sqlite3" } }
}
[:default, :one].each do |shard_name|
ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModelB.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_b')")
end
ActiveRecord::Base.connected_to(role: :secondary, shard: shard_name) do
ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
ShardConnectionTestModelB.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary_b')")
end
end
shard_one_latch = Concurrent::CountDownLatch.new
shard_default_latch = Concurrent::CountDownLatch.new
ShardConnectionTestModel.connection
thread = Thread.new do
ShardConnectionTestModel.connection
shard_default_latch.wait
assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
assert_equal "shard_key_default_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
shard_one_latch.count_down
end
ActiveRecord::Base.connected_to(shard: :one, role: :secondary) do
shard_default_latch.count_down
assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
assert_equal "shard_key_one_secondary_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
ActiveRecord::Base.connected_to(shard: :one, role: :secondary) do
assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
assert_equal "shard_key_one_secondary_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
end
shard_one_latch.wait
end
thread.join
ensure
tf_shard_one.close
tf_shard_one.unlink
tf_default.close
tf_default.unlink
tf_shard_one_reading.close
tf_shard_one_reading.unlink
tf_default_reading.close
tf_default_reading.unlink
tf_shard_one2.close
tf_shard_one2.unlink
tf_default2.close
tf_default2.unlink
tf_shard_one_reading2.close
tf_shard_one_reading2.unlink
tf_default_reading2.close
tf_default_reading2.unlink
end
end
end
end

View File

@ -1621,126 +1621,4 @@ if current_adapter?(:SQLite3Adapter) && !in_memory_db?
default_config.merge("replica" => true)
end
end
class MultipleFixtureLegacyConnectionsTest < ActiveRecord::TestCase
include ActiveRecord::TestFixtures
fixtures :dogs
def setup
@old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
@old_handler = ActiveRecord::Base.connection_handler
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(ENV["RAILS_ENV"], "readonly", readonly_config)
teardown_shared_connection_pool
handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
ActiveRecord::Base.connection_handler = handler
handler.establish_connection(db_config)
assert_deprecated do
ActiveRecord::Base.connection_handlers = {}
end
ActiveRecord::Base.connects_to(database: { writing: :default, reading: :readonly })
setup_shared_connection_pool
end
def teardown
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.connection_handler = @old_handler
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = false
end
def test_uses_writing_connection_for_fixtures
ActiveRecord::Base.connected_to(role: :reading) do
Dog.first
assert_nothing_raised do
ActiveRecord::Base.connected_to(role: :writing) { Dog.create! alias: "Doggo" }
end
end
end
def test_writing_and_reading_connections_are_the_same_with_legacy_handling
writing = ActiveRecord::Base.connection_handlers[:writing]
reading = ActiveRecord::Base.connection_handlers[:reading]
rw_conn = writing.retrieve_connection_pool("ActiveRecord::Base").connection
ro_conn = reading.retrieve_connection_pool("ActiveRecord::Base").connection
assert_equal rw_conn, ro_conn
teardown_shared_connection_pool
rw_conn = writing.retrieve_connection_pool("ActiveRecord::Base").connection
ro_conn = reading.retrieve_connection_pool("ActiveRecord::Base").connection
assert_not_equal rw_conn, ro_conn
end
def test_writing_and_reading_connections_are_the_same_for_non_default_shards_with_legacy_handling
ActiveRecord::Base.connects_to shards: {
default: { writing: :default, reading: :readonly },
two: { writing: :default, reading: :readonly }
}
writing = ActiveRecord::Base.connection_handlers[:writing]
reading = ActiveRecord::Base.connection_handlers[:reading]
rw_conn = writing.retrieve_connection_pool("ActiveRecord::Base", shard: :two).connection
ro_conn = reading.retrieve_connection_pool("ActiveRecord::Base", shard: :two).connection
assert_equal rw_conn, ro_conn
teardown_shared_connection_pool
rw_conn = writing.retrieve_connection_pool("ActiveRecord::Base", shard: :two).connection
ro_conn = reading.retrieve_connection_pool("ActiveRecord::Base", shard: :two).connection
assert_not_equal rw_conn, ro_conn
end
def test_only_existing_connections_are_replaced
ActiveRecord::Base.connects_to shards: {
default: { writing: :default, reading: :readonly },
two: { writing: :default }
}
setup_shared_connection_pool
assert_raises(ActiveRecord::ConnectionNotEstablished) do
ActiveRecord::Base.connected_to(role: :reading, shard: :two) do
ActiveRecord::Base.retrieve_connection
end
end
end
def test_only_existing_connections_are_restored
clean_up_legacy_connection_handlers
teardown_shared_connection_pool
assert_raises(ActiveRecord::ConnectionNotEstablished) do
ActiveRecord::Base.connected_to(role: :reading) do
ActiveRecord::Base.retrieve_connection
end
end
end
private
def config
{ "default" => default_config, "readonly" => readonly_config }
end
def default_config
{ "adapter" => "sqlite3", "database" => "test/fixtures/fixture_database.sqlite3" }
end
def readonly_config
default_config.merge("replica" => true)
end
end
end

View File

@ -168,19 +168,6 @@ def disable_extension!(extension, connection)
connection.reconnect!
end
def clean_up_legacy_connection_handlers
handler = ActiveRecord::Base.default_connection_handler
assert_deprecated do
ActiveRecord::Base.connection_handlers = {}
end
handler.connection_pool_names.each do |name|
next if ["ActiveRecord::Base", "ARUnit2Model", "Contact", "ContactSti", "FirstAbstractClass", "SecondAbstractClass"].include?(name)
handler.send(:owner_to_pool_manager).delete(name)
end
end
def clean_up_connection_handler
handler = ActiveRecord::Base.connection_handler
handler.instance_variable_get(:@owner_to_pool_manager).each do |owner, pool_manager|

View File

@ -74,36 +74,6 @@ class QueryCacheTest < ActiveRecord::TestCase
assert_cache :off
end
def test_query_cache_is_applied_to_legacy_connections_in_all_handlers
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_deprecated do
ActiveRecord::Base.connection_handlers = {
writing: ActiveRecord::Base.default_connection_handler,
reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
}
end
ActiveRecord::Base.connected_to(role: :reading) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
ActiveRecord::Base.establish_connection(db_config)
end
mw = middleware { |env|
reading_handler = ActiveRecord::Base.connection_handlers[:reading]
ro_pool = reading_handler.connection_pool_list
ro_conn = ro_pool.first.connection
assert_predicate ActiveRecord::Base.connection, :query_cache_enabled
assert_predicate ro_conn, :query_cache_enabled
}
mw.call({})
ensure
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = old_value
end
def test_query_cache_is_applied_to_all_connections
ActiveRecord::Base.connected_to(role: :reading) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
@ -125,74 +95,6 @@ class QueryCacheTest < ActiveRecord::TestCase
end
if Process.respond_to?(:fork) && !in_memory_db?
def test_query_cache_with_multiple_handlers_and_forked_processes_legacy_handling
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_deprecated do
ActiveRecord::Base.connection_handlers = {
writing: ActiveRecord::Base.default_connection_handler,
reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
}
end
ActiveRecord::Base.connected_to(role: :reading) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
ActiveRecord::Base.establish_connection(db_config)
end
rd, wr = IO.pipe
rd.binmode
wr.binmode
pid = fork {
rd.close
status = 0
middleware { |env|
begin
assert_cache :clean
# first request dirties cache
ActiveRecord::Base.connected_to(role: :reading) do
Post.first
assert_cache :dirty
end
# should clear the cache
Post.create!(title: "a new post", body: "and a body")
# fails because cache is still dirty
ActiveRecord::Base.connected_to(role: :reading) do
assert_cache :clean
Post.first
end
rescue Minitest::Assertion => e
wr.write Marshal.dump e
status = 1
end
}.call({})
wr.close
exit!(status)
}
wr.close
Process.waitpid pid
if !$?.success?
raise Marshal.load(rd.read)
else
assert_predicate $?, :success?
end
rd.close
ensure
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = old_value
end
def test_query_cache_with_forked_processes
ActiveRecord::Base.connected_to(role: :reading) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
@ -665,51 +567,6 @@ class QueryCacheTest < ActiveRecord::TestCase
}.call({})
end
def test_clear_query_cache_is_called_on_all_legacy_connections
skip "with in memory db, reading role won't be able to see database on writing role" if in_memory_db?
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
assert_deprecated do
ActiveRecord::Base.connection_handlers = {
writing: ActiveRecord::Base.default_connection_handler,
reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
}
end
ActiveRecord::Base.connected_to(role: :reading) do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
ActiveRecord::Base.establish_connection(db_config)
end
mw = middleware { |env|
ActiveRecord::Base.connected_to(role: :reading) do
@topic = Topic.first
end
assert @topic
ActiveRecord::Base.connected_to(role: :writing) do
@topic.title = "Topic title"
@topic.save!
end
assert_equal "Topic title", @topic.title
ActiveRecord::Base.connected_to(role: :reading) do
@topic = Topic.first
assert_equal "Topic title", @topic.title
end
}
mw.call({})
ensure
unless in_memory_db?
clean_up_legacy_connection_handlers
ActiveRecord.legacy_connection_handling = old_value
end
end
def test_clear_query_cache_is_called_on_all_connections
skip "with in memory db, reading role won't be able to see database on writing role" if in_memory_db?

View File

@ -22,46 +22,6 @@ class TestFixturesTest < ActiveRecord::TestCase
end
unless in_memory_db?
def test_doesnt_rely_on_active_support_test_case_specific_methods_with_legacy_connection_handling
old_value = ActiveRecord.legacy_connection_handling
ActiveRecord.legacy_connection_handling = true
tmp_dir = Dir.mktmpdir
File.write(File.join(tmp_dir, "zines.yml"), <<~YML)
going_out:
title: Hello
YML
klass = Class.new(Minitest::Test) do
include ActiveRecord::TestFixtures
self.fixture_path = tmp_dir
self.use_transactional_tests = true
fixtures :all
def test_run_successfully
assert_equal("Hello", Zine.first.title)
assert_equal("Hello", zines(:going_out).title)
end
end
old_handler = ActiveRecord::Base.connection_handler
ActiveRecord::Base.connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
assert_deprecated do
ActiveRecord::Base.connection_handlers = {}
end
ActiveRecord::Base.establish_connection(:arunit)
test_result = klass.new("test_run_successfully").run
assert_predicate(test_result, :passed?)
ensure
clean_up_legacy_connection_handlers
ActiveRecord::Base.connection_handler = old_handler
FileUtils.rm_r(tmp_dir)
ActiveRecord.legacy_connection_handling = old_value
end
def test_doesnt_rely_on_active_support_test_case_specific_methods
tmp_dir = Dir.mktmpdir
File.write(File.join(tmp_dir, "zines.yml"), <<~YML)

View File

@ -19,7 +19,6 @@ module ARTest
end
def self.connect
ActiveRecord.legacy_connection_handling = false
ActiveRecord.async_query_executor = :global_thread_pool
puts "Using #{connection_name}"
ActiveRecord::Base.logger = ActiveSupport::Logger.new("debug.log", 0, 100 * 1024 * 1024)

View File

@ -84,6 +84,8 @@ Please refer to the [Changelog][active-record] for detailed changes.
### Removals
* Remove support for `ActiveRecord.legacy_connection_handling`.
### Deprecations
### Notable changes

View File

@ -10,7 +10,6 @@ After reading this guide you will know:
* How to set up your application for multiple databases.
* How automatic connection switching works.
* How to use horizontal sharding for multiple databases.
* How to migrate from `legacy_connection_handling` to the new connection handling.
* What features are supported and what's still a work in progress.
--------------------------------------------------------------------------------
@ -477,41 +476,12 @@ config.active_record.shard_resolver = ->(request) {
}
```
## Migrate to the new connection handling
In Rails 6.1+, Active Record provides a new internal API for connection management.
In most cases applications will not need to make any changes except to opt-in to the
new behavior (if upgrading from 6.0 and below) by setting
[`config.active_record.legacy_connection_handling`][] to `false`. If you have a single database
application, no other changes will be required. If you have a multiple database application
the following changes are required if your application is using these methods:
* `connection_handlers` and `connection_handlers=` no longer works in the new connection
handling. If you were calling a method on one of the connection handlers, for example,
`connection_handlers[:reading].retrieve_connection_pool("ActiveRecord::Base")`
you will now need to update that call to be
`connection_handlers.retrieve_connection_pool("ActiveRecord::Base", role: :reading)`.
* Calls to `ActiveRecord::Base.connection_handler.prevent_writes` will need to be updated
to `ActiveRecord::Base.connection.preventing_writes?`.
* If you need all the pools, including writing and reading, a new method has been provided on
the handler. Call `connection_handler.all_connection_pools` to use this. In most cases though
you'll want writing or reading pools with `connection_handler.connection_pool_list(:writing)` or
`connection_handler.connection_pool_list(:reading)`.
* If you turn off `legacy_connection_handling` in your application, any method that's unsupported
will raise an error (i.e. `connection_handlers=`).
[`config.active_record.legacy_connection_handling`]: configuring.html#config-active-record-legacy-connection-handling
## Granular Database Connection Switching
In Rails 6.1 it's possible to switch connections for one database instead of
all databases globally. To use this feature you must first set
[`config.active_record.legacy_connection_handling`][] to `false` in your application
configuration. The majority of applications should not need to make any other
changes since the public APIs have the same behavior. See the above section for
how to enable and migrate away from `legacy_connection_handling`.
all databases globally.
With `legacy_connection_handling` set to `false`, any abstract connection class
With granular database connection switching, any abstract connection class
will be able to switch connections without affecting other connections. This
is useful for switching your `AnimalsRecord` queries to read from the replica
while ensuring your `ApplicationRecord` queries go to the primary.

View File

@ -163,7 +163,9 @@ module Rails
if respond_to?(:active_record)
active_record.has_many_inversing = true
active_record.legacy_connection_handling = false
if respond_to?(:legacy_connection_handling)
active_record.legacy_connection_handling = false
end
end
if respond_to?(:active_job)

View File

@ -3372,21 +3372,6 @@ module ApplicationTests
assert_equal false, Rails.application.config.assets.unknown_asset_fallback
end
test "legacy_connection_handling is false by default for new apps" do
app "development"
assert_equal false, Rails.application.config.active_record.legacy_connection_handling
end
test "legacy_connection_handling is not set before 6.1" do
remove_from_config '.*config\.load_defaults.*\n'
add_to_config 'config.load_defaults "6.0"'
app "development"
assert_nil Rails.application.config.active_record.legacy_connection_handling
end
test "ActionDispatch::Request.return_only_media_type_on_content_type is false by default" do
app "development"