identity_cache 0.4.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +5 -5
  2. data/.github/probots.yml +2 -0
  3. data/.github/workflows/ci.yml +92 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +5 -0
  6. data/CAVEATS.md +25 -0
  7. data/CHANGELOG.md +73 -19
  8. data/Gemfile +5 -1
  9. data/LICENSE +1 -1
  10. data/README.md +49 -27
  11. data/Rakefile +14 -5
  12. data/dev.yml +12 -16
  13. data/gemfiles/Gemfile.latest-release +8 -0
  14. data/gemfiles/Gemfile.min-supported +7 -0
  15. data/gemfiles/Gemfile.rails-edge +7 -0
  16. data/identity_cache.gemspec +29 -10
  17. data/lib/identity_cache.rb +78 -51
  18. data/lib/identity_cache/belongs_to_caching.rb +12 -40
  19. data/lib/identity_cache/cache_fetcher.rb +6 -5
  20. data/lib/identity_cache/cache_hash.rb +2 -2
  21. data/lib/identity_cache/cache_invalidation.rb +4 -11
  22. data/lib/identity_cache/cache_key_generation.rb +17 -65
  23. data/lib/identity_cache/cache_key_loader.rb +128 -0
  24. data/lib/identity_cache/cached.rb +7 -0
  25. data/lib/identity_cache/cached/association.rb +87 -0
  26. data/lib/identity_cache/cached/attribute.rb +123 -0
  27. data/lib/identity_cache/cached/attribute_by_multi.rb +37 -0
  28. data/lib/identity_cache/cached/attribute_by_one.rb +88 -0
  29. data/lib/identity_cache/cached/belongs_to.rb +100 -0
  30. data/lib/identity_cache/cached/embedded_fetching.rb +41 -0
  31. data/lib/identity_cache/cached/prefetcher.rb +61 -0
  32. data/lib/identity_cache/cached/primary_index.rb +96 -0
  33. data/lib/identity_cache/cached/recursive/association.rb +109 -0
  34. data/lib/identity_cache/cached/recursive/has_many.rb +9 -0
  35. data/lib/identity_cache/cached/recursive/has_one.rb +9 -0
  36. data/lib/identity_cache/cached/reference/association.rb +16 -0
  37. data/lib/identity_cache/cached/reference/has_many.rb +105 -0
  38. data/lib/identity_cache/cached/reference/has_one.rb +100 -0
  39. data/lib/identity_cache/configuration_dsl.rb +53 -215
  40. data/lib/identity_cache/encoder.rb +95 -0
  41. data/lib/identity_cache/expiry_hook.rb +36 -0
  42. data/lib/identity_cache/fallback_fetcher.rb +2 -1
  43. data/lib/identity_cache/load_strategy/eager.rb +28 -0
  44. data/lib/identity_cache/load_strategy/lazy.rb +71 -0
  45. data/lib/identity_cache/load_strategy/load_request.rb +20 -0
  46. data/lib/identity_cache/load_strategy/multi_load_request.rb +27 -0
  47. data/lib/identity_cache/mem_cache_store_cas.rb +53 -0
  48. data/lib/identity_cache/memoized_cache_proxy.rb +137 -58
  49. data/lib/identity_cache/parent_model_expiration.rb +46 -11
  50. data/lib/identity_cache/query_api.rb +102 -408
  51. data/lib/identity_cache/railtie.rb +8 -0
  52. data/lib/identity_cache/record_not_found.rb +6 -0
  53. data/lib/identity_cache/should_use_cache.rb +1 -0
  54. data/lib/identity_cache/version.rb +3 -2
  55. data/lib/identity_cache/with_primary_index.rb +136 -0
  56. data/lib/identity_cache/without_primary_index.rb +24 -3
  57. data/performance/cache_runner.rb +25 -73
  58. data/performance/cpu.rb +4 -3
  59. data/performance/externals.rb +4 -3
  60. data/performance/profile.rb +6 -5
  61. data/railgun.yml +16 -0
  62. metadata +60 -73
  63. data/.travis.yml +0 -30
  64. data/Gemfile.rails42 +0 -6
  65. data/Gemfile.rails50 +0 -6
  66. data/test/attribute_cache_test.rb +0 -110
  67. data/test/cache_fetch_includes_test.rb +0 -46
  68. data/test/cache_hash_test.rb +0 -14
  69. data/test/cache_invalidation_test.rb +0 -139
  70. data/test/deeply_nested_associated_record_test.rb +0 -19
  71. data/test/denormalized_has_many_test.rb +0 -211
  72. data/test/denormalized_has_one_test.rb +0 -160
  73. data/test/fetch_multi_test.rb +0 -308
  74. data/test/fetch_test.rb +0 -258
  75. data/test/fixtures/serialized_record.mysql2 +0 -0
  76. data/test/fixtures/serialized_record.postgresql +0 -0
  77. data/test/helpers/active_record_objects.rb +0 -106
  78. data/test/helpers/database_connection.rb +0 -72
  79. data/test/helpers/serialization_format.rb +0 -42
  80. data/test/helpers/update_serialization_format.rb +0 -24
  81. data/test/identity_cache_test.rb +0 -29
  82. data/test/index_cache_test.rb +0 -161
  83. data/test/memoized_attributes_test.rb +0 -49
  84. data/test/memoized_cache_proxy_test.rb +0 -107
  85. data/test/normalized_belongs_to_test.rb +0 -107
  86. data/test/normalized_has_many_test.rb +0 -231
  87. data/test/normalized_has_one_test.rb +0 -9
  88. data/test/prefetch_associations_test.rb +0 -364
  89. data/test/readonly_test.rb +0 -109
  90. data/test/recursive_denormalized_has_many_test.rb +0 -131
  91. data/test/save_test.rb +0 -82
  92. data/test/schema_change_test.rb +0 -112
  93. data/test/serialization_format_change_test.rb +0 -16
  94. data/test/test_helper.rb +0 -140
@@ -1,364 +0,0 @@
1
- require "test_helper"
2
-
3
- class PrefetchAssociationsTest < IdentityCache::TestCase
4
- NAMESPACE = IdentityCache.cache_namespace
5
-
6
- def setup
7
- super
8
- @bob = Item.create!(:title => 'bob')
9
- @joe = Item.create!(:title => 'joe')
10
- @fred = Item.create!(:title => 'fred')
11
- @bob_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:1"
12
- @joe_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:2"
13
- @fred_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:3"
14
- @tenth_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:10"
15
- end
16
-
17
- def test_prefetch_associations_on_fetched_records
18
- Item.send(:cache_belongs_to, :item)
19
- john = Item.create!(:title => 'john')
20
- jim = Item.create!(:title => 'jim')
21
- @bob.update_column(:item_id, john.id)
22
- @joe.update_column(:item_id, jim.id)
23
- items = Item.fetch_multi(@bob.id, @joe.id, @fred.id)
24
-
25
- spy = Spy.on(Item, :fetch_multi).and_call_through
26
-
27
- Item.prefetch_associations(:item, items)
28
-
29
- assert spy.calls.one?{ |call| call.args == [[john.id, jim.id]] }
30
- end
31
-
32
- def test_prefetch_associations_on_db_records
33
- Item.send(:cache_has_many, :associated_records, :embed => true)
34
- AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => :ids)
35
-
36
- setup_has_many_children_and_grandchildren(@bob)
37
-
38
- item = Item.find(@bob.id)
39
-
40
- assert_no_queries do
41
- assert_memcache_operations(1) do
42
- Item.prefetch_associations(:associated_records, [item])
43
- end
44
- assert_memcache_operations(0) do
45
- item.fetch_associated_records.each(&:fetch_deeply_associated_record_ids)
46
- end
47
- assert_memcache_operations(1) do
48
- Item.prefetch_associations({associated_records: :deeply_associated_records}, [item])
49
- end
50
- assert_memcache_operations(0) do
51
- item.fetch_associated_records.each(&:fetch_deeply_associated_records)
52
- end
53
- end
54
- end
55
-
56
- def test_prefetch_associations_without_using_cache
57
- Item.send(:cache_has_many, :associated_records, :embed => true)
58
-
59
- associated1 = @bob.associated_records.create!(name: 'foo')
60
- associated2 = @joe.associated_records.create!(name: 'bar')
61
- items = [@bob, @joe].map(&:reload)
62
-
63
- Item.transaction do
64
- assert_memcache_operations(0) do
65
- assert_queries(1) do
66
- Item.prefetch_associations(:associated_records, items)
67
- end
68
- assert_no_queries do
69
- assert_equal [[associated1], [associated2]], items.map(&:fetch_associated_records)
70
- end
71
- end
72
- end
73
- end
74
-
75
- def test_prefetch_associations_cached_belongs_to
76
- Item.send(:cache_belongs_to, :item)
77
- @bob.update_attributes!(item_id: @joe.id)
78
- @joe.update_attributes!(item_id: @fred.id)
79
- @bob.fetch_item
80
- @joe.fetch_item
81
- items = [@bob, @joe].map(&:reload)
82
-
83
- assert_no_queries do
84
- assert_memcache_operations(1) do
85
- Item.prefetch_associations(:item, items)
86
- end
87
- assert_memcache_operations(0) do
88
- items.each { |item| item.fetch_item }
89
- end
90
- assert_memcache_operations(0) do
91
- Item.prefetch_associations(:item, items)
92
- end
93
- end
94
- end
95
-
96
- def test_prefetch_associations_with_nil_cached_belongs_to
97
- Item.send(:cache_belongs_to, :item)
98
- @bob.update_attributes!(item_id: 1234)
99
- assert_nil @bob.fetch_item
100
-
101
- assert_no_queries do
102
- assert_memcache_operations(0) do
103
- Item.prefetch_associations(:item, [@bob])
104
- end
105
- end
106
- end
107
-
108
- def test_prefetch_associations_on_association
109
- AssociatedRecord.send(:cache_has_many, :deeply_associated_records, embed: true)
110
-
111
- setup_has_many_children_and_grandchildren(@bob)
112
-
113
- associated_records = @bob.associated_records
114
-
115
- assert_queries(1) do
116
- assert_memcache_operations(1) do
117
- AssociatedRecord.prefetch_associations(:deeply_associated_records, associated_records)
118
- end
119
- end
120
- assert_no_queries do
121
- assert_memcache_operations(0) do
122
- associated_records.each(&:fetch_deeply_associated_records)
123
- end
124
- end
125
- end
126
-
127
- def test_fetch_with_includes_option
128
- Item.send(:cache_belongs_to, :item)
129
- john = Item.create!(title: 'john')
130
- @bob.update_column(:item_id, john.id)
131
-
132
- spy = Spy.on(Item, :fetch_multi).and_call_through
133
-
134
- assert_equal @bob, Item.fetch(@bob.id, includes: :item)
135
-
136
- assert spy.calls.one?{ |call| call.args == [[john.id]] }
137
- end
138
-
139
- def test_fetch_multi_with_includes_option
140
- Item.send(:cache_belongs_to, :item)
141
- john = Item.create!(:title => 'john')
142
- jim = Item.create!(:title => 'jim')
143
- @bob.update_column(:item_id, john.id)
144
- @joe.update_column(:item_id, jim.id)
145
-
146
- spy = Spy.on(Item, :fetch_multi).and_call_through
147
-
148
- assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id, :includes => :item)
149
-
150
- assert spy.calls.one?{ |call| call.args == [[john.id, jim.id]] }
151
- end
152
-
153
- def test_fetch_multi_batch_fetches_non_embedded_first_level_has_many_associations
154
- Item.send(:cache_has_many, :associated_records, :embed => :ids)
155
-
156
- child_records = []
157
- [@bob, @joe].each do |parent|
158
- 3.times do |i|
159
- child_records << (child_record = parent.associated_records.create!(:name => i.to_s))
160
- AssociatedRecord.fetch(child_record.id)
161
- end
162
- end
163
-
164
- Item.fetch_multi(@bob.id, @joe.id) # populate the cache entries and associated children ID variables
165
-
166
- assert_memcache_operations(2) do
167
- @cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => :associated_records)
168
- assert_equal child_records[0..2].sort, @cached_bob.fetch_associated_records.sort
169
- assert_equal child_records[3..5].sort, @cached_joe.fetch_associated_records.sort
170
- end
171
- end
172
-
173
- def test_fetch_multi_batch_fetches_first_level_belongs_to_associations
174
- AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
175
-
176
- @bob_child = @bob.associated_records.create!(:name => "bob child")
177
- @fred_child = @fred.associated_records.create!(:name => "fred child")
178
-
179
- # populate the cache entries and associated children ID variables
180
- AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id)
181
- Item.fetch_multi(@bob.id, @fred.id)
182
-
183
- assert_memcache_operations(2) do
184
- @cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => :item)
185
- assert_equal @bob, @cached_bob_child.fetch_item
186
- assert_equal @fred, @cached_fred_child.fetch_item
187
- end
188
- end
189
-
190
- def test_fetch_multi_batch_fetches_first_level_associations_who_dont_include_identity_cache
191
- NotCachedRecord.include(IdentityCache::WithoutPrimaryIndex)
192
- Item.send(:cache_has_many, :not_cached_records, :embed => true)
193
-
194
- @bob_child = @bob.not_cached_records.create!(:name => "bob child")
195
- @fred_child = @fred.not_cached_records.create!(:name => "fred child")
196
-
197
- # populate the cache entries and associated children ID variables
198
- Item.fetch_multi(@bob.id, @fred.id)
199
-
200
- assert_memcache_operations(1) do
201
- @cached_bob_child, @cached_fred_child = Item.fetch_multi(@bob.id, @fred.id, :includes => :not_cached_records)
202
- end
203
- end
204
-
205
- def test_fetch_multi_batch_fetches_non_embedded_second_level_has_many_associations
206
- Item.send(:cache_has_many, :associated_records, :embed => :ids)
207
- AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => :ids)
208
-
209
- _child_records, grandchildren = setup_has_many_children_and_grandchildren(@bob, @joe)
210
-
211
- assert_memcache_operations(3) do
212
- @cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated_records => :deeply_associated_records})
213
- bob_children = @cached_bob.fetch_associated_records.sort
214
- joe_children = @cached_joe.fetch_associated_records.sort
215
-
216
- assert_equal grandchildren[0..2].sort, bob_children[0].fetch_deeply_associated_records.sort
217
- assert_equal grandchildren[3..5].sort, bob_children[1].fetch_deeply_associated_records.sort
218
- assert_equal grandchildren[6..8].sort, bob_children[2].fetch_deeply_associated_records.sort
219
- assert_equal grandchildren[9..11].sort, joe_children[0].fetch_deeply_associated_records.sort
220
- assert_equal grandchildren[12..14].sort, joe_children[1].fetch_deeply_associated_records.sort
221
- assert_equal grandchildren[15..17].sort, joe_children[2].fetch_deeply_associated_records.sort
222
- end
223
- end
224
-
225
- def test_fetch_multi_batch_fetches_non_embedded_second_level_belongs_to_associations
226
- Item.send(:cache_belongs_to, :item, :embed => false)
227
- AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
228
-
229
- @bob_child = @bob.associated_records.create!(:name => "bob child")
230
- @fred_child = @fred.associated_records.create!(:name => "fred child")
231
- @bob.update_attribute(:item_id, @bob.id)
232
- @fred.update_attribute(:item_id, @fred.id)
233
-
234
- # populate the cache entries and associated children ID variables
235
- AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id)
236
- Item.fetch_multi(@bob.id, @fred.id)
237
-
238
- assert_memcache_operations(3) do
239
- @cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => {:item => :item})
240
-
241
- @cached_bob_parent = @cached_bob_child.fetch_item
242
- @cached_fred_parent = @cached_fred_child.fetch_item
243
- assert_equal @bob, @cached_bob_parent.fetch_item
244
- assert_equal @fred, @cached_fred_parent.fetch_item
245
- end
246
- end
247
-
248
- def test_fetch_multi_doesnt_batch_fetches_belongs_to_associations_if_the_foreign_key_isnt_present
249
- AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
250
- @child = AssociatedRecord.create!(:name => "bob child")
251
- # populate the cache entry
252
- AssociatedRecord.fetch_multi(@child.id)
253
-
254
- assert_memcache_operations(1) do
255
- @cached_child = AssociatedRecord.fetch_multi(@child.id, :includes => :item)
256
- end
257
- end
258
-
259
-
260
- def test_fetch_multi_batch_fetches_non_embedded_second_level_associations_through_embedded_first_level_has_many_associations
261
- Item.send(:cache_has_many, :associated_records, :embed => true)
262
- AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => :ids)
263
-
264
- _child_records, grandchildren = setup_has_many_children_and_grandchildren(@bob, @joe)
265
-
266
- assert_memcache_operations(2) do
267
- @cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated_records => :deeply_associated_records})
268
- bob_children = @cached_bob.fetch_associated_records.sort
269
- joe_children = @cached_joe.fetch_associated_records.sort
270
-
271
- assert_equal grandchildren[0..2].sort, bob_children[0].fetch_deeply_associated_records.sort
272
- assert_equal grandchildren[3..5].sort, bob_children[1].fetch_deeply_associated_records.sort
273
- assert_equal grandchildren[6..8].sort, bob_children[2].fetch_deeply_associated_records.sort
274
- assert_equal grandchildren[9..11].sort, joe_children[0].fetch_deeply_associated_records.sort
275
- assert_equal grandchildren[12..14].sort, joe_children[1].fetch_deeply_associated_records.sort
276
- assert_equal grandchildren[15..17].sort, joe_children[2].fetch_deeply_associated_records.sort
277
- end
278
- end
279
-
280
- def test_fetch_multi_batch_fetches_non_embedded_second_level_associations_through_embedded_first_level_has_one_associations
281
- Item.send(:cache_has_one, :associated, :embed => true)
282
- AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => :ids)
283
-
284
- @bob_child = @bob.create_associated!(:name => "bob child")
285
- @joe_child = @joe.create_associated!(:name => "joe child")
286
-
287
- grandchildren = setup_grandchildren(@bob_child, @joe_child)
288
- AssociatedRecord.fetch_multi(@bob_child.id, @joe_child.id)
289
- Item.fetch_multi(@bob.id, @joe.id)
290
-
291
- assert_memcache_operations(2) do
292
- @cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated => :deeply_associated_records})
293
- bob_child = @cached_bob.fetch_associated
294
- joe_child = @cached_joe.fetch_associated
295
-
296
- assert_equal grandchildren[0..2].sort, bob_child.fetch_deeply_associated_records.sort
297
- assert_equal grandchildren[3..5].sort, joe_child.fetch_deeply_associated_records.sort
298
- end
299
- end
300
-
301
- def test_find_batch_coerces_ids_to_primary_key_type
302
- mock_relation = mock("ActiveRecord::Relation")
303
- Item.expects(:where).returns(mock_relation)
304
- mock_relation.expects(:includes).returns(stub(:to_a => [@bob, @joe, @fred]))
305
-
306
- Item.send(:find_batch, [@bob, @joe, @fred].map(&:id).map(&:to_s))
307
- end
308
-
309
- def test_fetch_by_index_with_includes_option
310
- Item.send(:cache_belongs_to, :item)
311
- Item.cache_index :title
312
- john = Item.create!(title: 'john')
313
- @bob.update_column(:item_id, john.id)
314
-
315
- spy = Spy.on(Item, :fetch_multi).and_call_through
316
-
317
- assert_equal [@bob], Item.fetch_by_title('bob', includes: :item)
318
-
319
- assert spy.calls.one?{ |call| call.args == [[john.id]] }
320
- end
321
-
322
- def test_fetch_by_unique_index_with_includes_option
323
- Item.send(:cache_belongs_to, :item)
324
- Item.cache_index :title, :unique => true
325
- john = Item.create!(title: 'john')
326
- @bob.update_column(:item_id, john.id)
327
-
328
- spy = Spy.on(Item, :fetch_multi).and_call_through
329
-
330
- assert_equal @bob, Item.fetch_by_title('bob', includes: :item)
331
-
332
- assert spy.calls.one?{ |call| call.args == [[john.id]] }
333
- end
334
-
335
- private
336
-
337
- def setup_has_many_children_and_grandchildren(*parents)
338
- child_records = []
339
- grandchildren = []
340
-
341
- parents.each do |parent|
342
- 3.times do |i|
343
- child_records << (child = parent.associated_records.create!(:name => i.to_s))
344
- grandchildren.concat setup_grandchildren(child)
345
- AssociatedRecord.fetch(child.id)
346
- end
347
- end
348
-
349
- Item.fetch_multi(*parents.map(&:id)) # populate the cache entries and associated children ID variables
350
-
351
- return child_records, grandchildren
352
- end
353
-
354
- def setup_grandchildren(*children)
355
- grandchildren = []
356
- children.each do |child|
357
- 3.times do |j|
358
- grandchildren << (grandchild = child.deeply_associated_records.create!(:name => j.to_s))
359
- DeeplyAssociatedRecord.fetch(grandchild.id)
360
- end
361
- end
362
- grandchildren
363
- end
364
- end
@@ -1,109 +0,0 @@
1
- require "test_helper"
2
-
3
- class ReadonlyTest < IdentityCache::TestCase
4
- def setup
5
- super
6
- @key, @value = 'foo', 'bar'
7
- @record = Item.new
8
- @record.id = 1
9
- @record.title = 'bob'
10
- @bob = Item.create!(:title => 'bob')
11
- @joe = Item.create!(:title => 'joe')
12
- @fred = Item.create!(:title => 'fred')
13
- IdentityCache.cache.clear
14
- IdentityCache.readonly = true
15
- end
16
-
17
- def teardown
18
- IdentityCache.readonly = nil
19
- super
20
- end
21
-
22
- def test_write_should_not_update_cache
23
- assert_memcache_operations(0) do
24
- fetcher.write(@key, @value)
25
- end
26
- assert_nil backend.read(@key)
27
- end
28
-
29
- def test_delete_should_update_cache
30
- backend.write(@key, @value)
31
- fetcher.delete(@key)
32
- assert_equal deleted_value, backend.read(@key)
33
- end
34
-
35
- def test_clear_should_update_cache
36
- backend.write(@key, @value)
37
- fetcher.clear
38
- assert_nil backend.read(@key)
39
- end
40
-
41
- def test_fetch_should_not_update_cache
42
- fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
43
- Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
44
-
45
- assert_readonly_fetch do
46
- assert_equal @record, Item.fetch(1)
47
- end
48
- assert_nil backend.read(@record.primary_cache_index_key)
49
- assert fetch.has_been_called_with?(@record.primary_cache_index_key)
50
- end
51
-
52
- def test_fetch_multi_should_not_update_cache
53
- fetch_multi = Spy.on(IdentityCache.cache, :fetch_multi).and_call_through
54
-
55
- assert_readonly_fetch_multi do
56
- assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
57
- end
58
- keys = [@bob, @joe, @fred].map(&:primary_cache_index_key)
59
- assert_empty backend.read_multi(*keys)
60
- assert fetch_multi.has_been_called_with?(*keys)
61
- end
62
-
63
- protected
64
-
65
- def assert_readonly_fetch
66
- cas = Spy.on(backend, :cas).and_call_through
67
- yield
68
- assert cas.has_been_called?
69
- end
70
-
71
- def assert_readonly_fetch_multi
72
- cas_multi = Spy.on(backend, :cas_multi).and_call_through
73
- yield
74
- assert cas_multi.has_been_called?
75
- end
76
-
77
- def deleted_value
78
- IdentityCache::DELETED
79
- end
80
- end
81
-
82
- class FallbackReadonlyTest < ReadonlyTest
83
- def setup
84
- super
85
- IdentityCache.cache_backend = @backend = ActiveSupport::Cache::MemoryStore.new
86
- end
87
-
88
- protected
89
-
90
- def assert_readonly_fetch
91
- read = Spy.on(backend, :read).and_call_through
92
- write = Spy.on(backend, :write).and_call_through
93
- yield
94
- assert read.has_been_called?
95
- refute write.has_been_called?
96
- end
97
-
98
- def assert_readonly_fetch_multi
99
- read_multi = Spy.on(backend, :read_multi).and_call_through
100
- write = Spy.on(backend, :write).and_call_through
101
- yield
102
- assert read_multi.has_been_called?
103
- refute write.has_been_called?
104
- end
105
-
106
- def deleted_value
107
- nil
108
- end
109
- end