# frozen_string_literal: true require "cases/helper" require "rack" module ActiveRecord module ConnectionAdapters class ConnectionManagementTest < ActiveRecord::TestCase self.use_transactional_tests = false class App attr_reader :calls def initialize @calls = [] end def call(env) @calls << env [200, {}, ["hi mom"]] end end def setup @env = {} @app = App.new @management = middleware(@app) # make sure we have an active connection assert ActiveRecord::Base.connection assert_predicate ActiveRecord::Base.connection_handler, :active_connections? end def test_app_delegation manager = middleware(@app) manager.call @env assert_equal [@env], @app.calls end def test_body_responds_to_each _, _, body = @management.call(@env) bits = [] body.each { |bit| bits << bit } assert_equal ["hi mom"], bits end def test_connections_are_cleared_after_body_close _, _, body = @management.call(@env) body.close assert_not_predicate ActiveRecord::Base.connection_handler, :active_connections? end def test_active_connections_are_not_cleared_on_body_close_during_transaction ActiveRecord::Base.transaction do _, _, body = @management.call(@env) body.close assert_predicate ActiveRecord::Base.connection_handler, :active_connections? end end def test_connections_closed_if_exception app = Class.new(App) { def call(env); raise NotImplementedError; end }.new explosive = middleware(app) assert_raises(NotImplementedError) { explosive.call(@env) } assert_not_predicate ActiveRecord::Base.connection_handler, :active_connections? end def test_connections_not_closed_if_exception_inside_transaction ActiveRecord::Base.transaction do app = Class.new(App) { def call(env); raise RuntimeError; end }.new explosive = middleware(app) assert_raises(RuntimeError) { explosive.call(@env) } assert_predicate ActiveRecord::Base.connection_handler, :active_connections? end end test "doesn't clear active connections when running in a test case" do executor.wrap do @management.call(@env) assert_predicate ActiveRecord::Base.connection_handler, :active_connections? end end test "proxy is polite to its body and responds to it" do body = Class.new(String) { def to_path; "/path"; end }.new app = lambda { |_| [200, {}, body] } response_body = middleware(app).call(@env)[2] assert_respond_to response_body, :to_path assert_equal "/path", response_body.to_path end test "doesn't mutate the original response" do original_response = [200, {}, "hi"] app = lambda { |_| original_response } middleware(app).call(@env)[2] assert_equal "hi", original_response.last end private def executor @executor ||= Class.new(ActiveSupport::Executor).tap do |exe| ActiveRecord::QueryCache.install_executor_hooks(exe) end end def middleware(app) lambda do |env| a, b, c = executor.wrap { app.call(env) } [a, b, Rack::BodyProxy.new(c) { }] end end end end end