diff --git a/test/helpers/active_record_objects.rb b/test/helpers/active_record_objects.rb index cfed8994..e6e60cb6 100644 --- a/test/helpers/active_record_objects.rb +++ b/test/helpers/active_record_objects.rb @@ -45,6 +45,8 @@ def teardown_models Object.send(:remove_const, 'Deeply') Object.send(:remove_const, 'CustomMasterRecord') Object.send(:remove_const, 'CustomChildRecord') + Object.send(:remove_const, 'LazyModel') + $LOADED_FEATURES.reject! { |feature| feature.include?("test/helpers/lazy_model/") } IdentityCache.const_get(:ParentModelExpiration).send(:lazy_hooks).clear end end diff --git a/test/helpers/database_connection.rb b/test/helpers/database_connection.rb index 7c7539bb..713e4280 100644 --- a/test/helpers/database_connection.rb +++ b/test/helpers/database_connection.rb @@ -59,7 +59,10 @@ def self.create_tables custom_master_records: [[:integer, :master_primary_key], id: false, primary_key: 'master_primary_key'], custom_child_records: [ [:integer, :child_primary_key], [:integer, :master_id], id: false, primary_key: 'child_primary_key' - ] + ], + lazy_as: [[:string, :name]], + lazy_bs: [[:string, :name], [:integer, :a_id]], + lazy_cs: [[:string, :name], [:integer, :b_id]], } DEFAULT_CONFIG = { diff --git a/test/helpers/lazy_model/a.rb b/test/helpers/lazy_model/a.rb new file mode 100644 index 00000000..68d83d62 --- /dev/null +++ b/test/helpers/lazy_model/a.rb @@ -0,0 +1,8 @@ +module LazyModel + class A < ActiveRecord::Base + self.table_name = "lazy_as" + include IdentityCache + has_many :bs, class_name: "::LazyModel::B" + cache_has_many :bs, embed: true + end +end diff --git a/test/helpers/lazy_model/b.rb b/test/helpers/lazy_model/b.rb new file mode 100644 index 00000000..345f35c6 --- /dev/null +++ b/test/helpers/lazy_model/b.rb @@ -0,0 +1,9 @@ +module LazyModel + class B < ActiveRecord::Base + self.table_name = "lazy_bs" + include IdentityCache + belongs_to :a, class_name: "::LazyModel::A", inverse_of: :bs + has_one :c, class_name: "::LazyModel::C", inverse_of: :b + cache_has_one :c + end +end diff --git a/test/helpers/lazy_model/c.rb b/test/helpers/lazy_model/c.rb new file mode 100644 index 00000000..a2ce4633 --- /dev/null +++ b/test/helpers/lazy_model/c.rb @@ -0,0 +1,7 @@ +module LazyModel + class C < ActiveRecord::Base + self.table_name = "lazy_cs" + include IdentityCache + belongs_to :b, class_name: "::LazyModel::B", inverse_of: :c + end +end diff --git a/test/helpers/models.rb b/test/helpers/models.rb index d09e14ec..8852daac 100644 --- a/test/helpers/models.rb +++ b/test/helpers/models.rb @@ -88,3 +88,9 @@ class CustomChildRecord < ActiveRecord::Base belongs_to :custom_master_record, foreign_key: :master_id self.primary_key = 'child_primary_key' end + +module LazyModel + autoload :A, "helpers/lazy_model/a.rb" + autoload :B, "helpers/lazy_model/b.rb" + autoload :C, "helpers/lazy_model/c.rb" +end diff --git a/test/lazy_hook_test.rb b/test/lazy_hook_test.rb new file mode 100644 index 00000000..17c3f92d --- /dev/null +++ b/test/lazy_hook_test.rb @@ -0,0 +1,44 @@ +require "test_helper" + +class LazyHookTest < IdentityCache::TestCase + def test_expires_unloaded_lazy_parent_models + # Populate cache + a = LazyModel::A.create!(name: "Initial A") + b = a.bs.create!(name: "Initial B") + c = b.create_c!(name: "Initial C") + + ids = { + a: a.id, + b: b.id, + c: c.id, + } + + # Warm cache + LazyModel::A.fetch(ids[:a]).fetch_bs.first.fetch_c + + # Clear lazyloaded code to simulate code that isn't eager loaded + reset_loaded_code + LazyModel::C.find(ids[:c]).update!(name: "Updated C") + + refute(lazy_model_loaded?(:A)) + refute(lazy_model_loaded?(:B)) + + queries = count_queries do + c = LazyModel::A.fetch(ids[:a]).fetch_bs.first.fetch_c + assert_equal("Updated C", c.name) + end + + assert_equal(0, queries) + end + + private + + def reset_loaded_code + teardown_models + setup_models + end + + def lazy_model_loaded?(name) + !LazyModel.autoload?(name) + end +end