From 74d914248b9cedb6db3c8a1cf17778b35ac56b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Ska=C5=82acki?= Date: Tue, 28 Jan 2020 10:42:14 +0100 Subject: [PATCH] Don't hack into descendants tracker in specs Active Support features its own class hierarchy tracker, which was preventing anonymous classes from being garbage collected due to a bug, which has been fixed in Rails 6.0. For older Rails version, a hack is needed to make tests independent from each other. For Rails 6+, this hack no longer works, but is also unnecessary. Although another workaround is needed. See comment in the Ruby changeset for details. --- spec/features/active_record_spec.rb | 31 ++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/spec/features/active_record_spec.rb b/spec/features/active_record_spec.rb index ba14476..71eff76 100644 --- a/spec/features/active_record_spec.rb +++ b/spec/features/active_record_spec.rb @@ -38,10 +38,35 @@ # fortunately, DescendantsTracker is modified extremely rarely (no changes # to AST since 2012), therefore I expect that this new approach will # require much less maintenance than stubbing we did. + # + # ----- + # 2020-01 + # + # From Rails 6.0, DescendantsTracker uses weak references, and no longer + # blocks garbage collection of anonymous classes. See: + # https://github.com/rails/rails/pull/31442 + # + # However, instances of these classes, which are bound to example life cycle + # via #let helpers, also hold the references, hence garbage collection must + # be postponed till example life cycle ends. + # + # Consequently, #after hooks cannot be used, as they are run too early for + # this purpose, but fortunately this can be worked around by + # before(:example) + after(:all) combo. after do - ::ActiveSupport::DescendantsTracker. - class_variable_get("@@direct_descendants")[::ActiveRecord::Base]. - delete(user_class_definition) + if ::ActiveSupport.gem_version < Gem::Version.new("6.0.0") + ::ActiveSupport::DescendantsTracker. + class_variable_get("@@direct_descendants")[::ActiveRecord::Base]. + delete(user_class_definition) + end + end + + before do + GC.start + end + + after(:all) do + GC.start end # Rails 5.2 seems to reset connection shortly after Combustion gets its job,