cached_record 0.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.
@@ -0,0 +1,616 @@
1
+ require File.expand_path("../../../test_helper", __FILE__)
2
+
3
+ module Unit
4
+ module ORM
5
+ class TestDataMapper < MiniTest::Test
6
+
7
+ class Article
8
+ include DataMapper::Resource
9
+ storage_names[:default] = "articles"
10
+ property :id, Serial, :key => true
11
+ property :title, String
12
+ property :content, Text
13
+ as_cache :redis
14
+ end
15
+
16
+ class Barticle
17
+ include DataMapper::Resource
18
+ storage_names[:default] = "articles"
19
+ property :id, Serial, :key => true
20
+ property :title, String
21
+ property :content, Text
22
+ as_cache :redis, :only => [:title, :content]
23
+ end
24
+
25
+ class Carticle
26
+ include DataMapper::Resource
27
+ storage_names[:default] = "articles"
28
+ property :id, Serial, :key => true
29
+ property :title, String
30
+ property :content, Text
31
+ as_cache :redis, :only => [], :memoize => [:random_array]
32
+
33
+ def random_array
34
+ @random_array ||= [rand(10)]
35
+ end
36
+ end
37
+
38
+ class Darticle
39
+ include DataMapper::Resource
40
+ storage_names[:default] = "articles"
41
+ property :id, Serial, :key => true
42
+ property :title, String
43
+ property :content, Text
44
+ as_cache :redis, :only => [:title, :content], :memoize => {:random_array => :@array}
45
+
46
+ def random_array
47
+ @array ||= [rand(10)]
48
+ end
49
+ end
50
+
51
+ class Earticle
52
+ include DataMapper::Resource
53
+ storage_names[:default] = "articles"
54
+ property :id, Serial, :key => true
55
+ property :title, String
56
+ property :content, Text
57
+ as_cache :redis, :only => [:title, :content], :memoize => {:random_array => :@array}, :include_root => true
58
+
59
+ def random_array
60
+ @array ||= [rand(10)]
61
+ end
62
+ end
63
+
64
+ class Farticle
65
+ include DataMapper::Resource
66
+ storage_names[:default] = "articles"
67
+ property :id, Serial, :key => true
68
+ property :title, String
69
+ property :content, Text
70
+ as_memoized_cache :redis, :only => [:title, :content], :memoize => {:random_array => :@array}, :include_root => true
71
+
72
+ def random_array
73
+ @array ||= [rand(10)]
74
+ end
75
+ end
76
+
77
+ class Garticle
78
+ include DataMapper::Resource
79
+ storage_names[:default] = "articles"
80
+ property :id, Serial, :key => true
81
+ property :title, String
82
+ belongs_to :author, :model => "Unit::ORM::TestDataMapper::User"
83
+ has n, :comments, :model => "Unit::ORM::TestDataMapper::Comment", :child_key => "article_id"
84
+ has n, :taggings, :model => "Unit::ORM::TestDataMapper::Tagging", :child_key => "article_id"
85
+ has n, :tags, :through => :taggings
86
+ as_memoized_cache :redis, :only => [:title], :include => [:author, :comments, :tags]
87
+ end
88
+
89
+ class User
90
+ include DataMapper::Resource
91
+ storage_names[:default] = "users"
92
+ property :id, Serial, :key => true
93
+ property :name, String
94
+ has 1, :foo, :model => "Unit::ORM::TestDataMapper::Article", :child_key => "foo_id"
95
+ as_memoized_cache :memcached, :only => [:name], :include => [:foo]
96
+ end
97
+
98
+ class Comment
99
+ include DataMapper::Resource
100
+ storage_names[:default] = "comments"
101
+ property :id, Serial, :key => true
102
+ property :content, Text
103
+ belongs_to :article, :model => "Unit::ORM::TestDataMapper::Garticle"
104
+ belongs_to :poster, :model => "Unit::ORM::TestDataMapper::User"
105
+ as_memoized_cache :redis, :only => [:content], :include => [:poster]
106
+ end
107
+
108
+ class Tag
109
+ include DataMapper::Resource
110
+ storage_names[:default] = "tags"
111
+ property :id, Serial, :key => true
112
+ property :name, String
113
+ has n, :articles, :model => "Unit::ORM::TestDataMapper::Garticle", :through => Resource
114
+ as_memoized_cache :redis, :only => [:name]
115
+ end
116
+
117
+ class Tagging
118
+ include DataMapper::Resource
119
+ storage_names[:default] = "articles_tags"
120
+ property :id, Serial, :key => true
121
+ belongs_to :article, :model => "Unit::ORM::TestDataMapper::Garticle"
122
+ belongs_to :tag, :model => "Unit::ORM::TestDataMapper::Tag"
123
+ end
124
+
125
+ class Harticle
126
+ include DataMapper::Resource
127
+ storage_names[:default] = "articles"
128
+ property :id, Serial, :key => true
129
+ property :title, String
130
+ as_memoized_cache :redis, :only => [:title], :expire => 2.seconds
131
+ end
132
+
133
+ class Jarticle
134
+ include DataMapper::Resource
135
+ storage_names[:default] = "articles"
136
+ property :id, Serial, :key => true
137
+ property :title, String
138
+ as_memoized_cache :redis, :only => [:title], :retain => 4.seconds
139
+ end
140
+
141
+ DataMapper.finalize
142
+
143
+ describe CachedRecord::ORM::DataMapper do
144
+ describe "when DataMapper is not defined" do
145
+ it "knows not to setup DataMapper::Resource" do
146
+ CachedRecord::ORM::DataMapper.expects(:setup?).returns false
147
+ DataMapper::Resource.expects(:send).with(:include, CachedRecord::ORM::InstanceMethods).never
148
+ DataMapper::Resource.expects(:send).with(:include, CachedRecord::ORM::DataMapper::InstanceMethods).never
149
+ CachedRecord::ORM::DataMapper.setup
150
+ end
151
+ end
152
+
153
+ describe "when DataMapper is defined" do
154
+ it "knows to setup DataMapper::Resource" do
155
+ CachedRecord::ORM::DataMapper.expects(:setup?).returns true
156
+ DataMapper::Resource.expects(:send).with(:include, CachedRecord::ORM::InstanceMethods)
157
+ DataMapper::Resource.expects(:send).with(:include, CachedRecord::ORM::DataMapper::InstanceMethods)
158
+ CachedRecord::ORM::DataMapper.setup
159
+ end
160
+ end
161
+
162
+ describe "DataMapper::Resource included" do
163
+ before do
164
+ @redis = Redis.new
165
+ @memcached = Dalli::Client.new
166
+ end
167
+
168
+ describe "Article" do
169
+ it "returns its cache JSON hash" do
170
+ assert_equal_hashes({
171
+ :id => 1,
172
+ :title => "Behold! It's CachedRecord!",
173
+ :content => "Cache ORM instances to avoid database queries",
174
+ :foo_id => 2
175
+ }, Article.get(1).as_cache_json)
176
+ end
177
+ it "can be stored in the cache store" do
178
+ Article.cached 1
179
+ assert_equal_hashes({
180
+ :id => 1,
181
+ :title => "Behold! It's CachedRecord!",
182
+ :content => "Cache ORM instances to avoid database queries",
183
+ :foo_id => 2
184
+ }, @redis.get("unit.orm.test_data_mapper.article.1"))
185
+ end
186
+ it "can be fetched from the cache store" do
187
+ Article.expects(:get).never
188
+ @redis.set(
189
+ "unit.orm.test_data_mapper.article.1", {
190
+ :id => 1,
191
+ :title => "Behold! It's CachedRecord!",
192
+ :content => "Cache ORM instances to avoid database queries"
193
+ }.to_json
194
+ )
195
+ assert_equal_hashes({
196
+ :id => 1,
197
+ :title => "Behold! It's CachedRecord!",
198
+ :content => "Cache ORM instances to avoid database queries",
199
+ :foo_id => 2
200
+ }, Article.cached(1).attributes)
201
+ end
202
+ it "is not a new" do
203
+ assert_equal false, Article.cached(1).new?
204
+ end
205
+ end
206
+
207
+ describe "Barticle" do
208
+ it "returns its cache JSON hash" do
209
+ assert_equal_hashes({
210
+ :id => 1,
211
+ :title => "Behold! It's CachedRecord!",
212
+ :content => "Cache ORM instances to avoid database queries"
213
+ }, Barticle.get(1).as_cache_json)
214
+ end
215
+ it "can be stored in the cache store" do
216
+ Barticle.cached(1)
217
+ assert_equal_hashes({
218
+ :id => 1,
219
+ :title => "Behold! It's CachedRecord!",
220
+ :content => "Cache ORM instances to avoid database queries"
221
+ }, @redis.get("unit.orm.test_data_mapper.barticle.1"))
222
+ end
223
+ it "can be fetched from the cache store" do
224
+ Barticle.expects(:get).never
225
+ @redis.set(
226
+ "unit.orm.test_data_mapper.barticle.1", {
227
+ "id" => 1,
228
+ "title" => "Behold! It's CachedRecord!",
229
+ "content" => "Cache ORM instances to avoid database queries"
230
+ }.to_json
231
+ )
232
+ assert_equal_hashes({
233
+ :id => 1,
234
+ :title => "Behold! It's CachedRecord!",
235
+ :content => "Cache ORM instances to avoid database queries"
236
+ }, Barticle.cached(1).attributes)
237
+ end
238
+ end
239
+
240
+ describe "Carticle" do
241
+ it "returns its cache JSON hash" do
242
+ c = Carticle.get(1)
243
+ c.expects(:rand).returns(5)
244
+ assert_equal_hashes({
245
+ :id => 1,
246
+ :@random_array => [5]
247
+ }, c.as_cache_json)
248
+ end
249
+ it "can be stored in the cache store" do
250
+ Carticle.any_instance.expects(:rand).returns(4)
251
+ Carticle.cached(1)
252
+ assert_equal_hashes({
253
+ :id => 1,
254
+ :@random_array => [4]
255
+ }, @redis.get("unit.orm.test_data_mapper.carticle.1"))
256
+ end
257
+ it "can be fetched from the cache store" do
258
+ Carticle.expects(:get).never
259
+ @redis.set(
260
+ "unit.orm.test_data_mapper.carticle.1", {
261
+ :id => 1,
262
+ :title => "Behold! It's CachedRecord!",
263
+ :content => "Cache ORM instances to avoid database queries",
264
+ :@random_array => [3]
265
+ }.to_json
266
+ )
267
+ assert_equal_hashes({
268
+ :id => 1,
269
+ :title => "Behold! It's CachedRecord!",
270
+ :content => "Cache ORM instances to avoid database queries"
271
+ }, Carticle.cached(1).attributes)
272
+ assert_equal(
273
+ true, Carticle.cached(1).instance_variables.include?(:@random_array)
274
+ )
275
+ assert_equal([
276
+ 3
277
+ ], Carticle.cached(1).instance_variable_get(:@random_array))
278
+ end
279
+ end
280
+
281
+ describe "Darticle" do
282
+ it "returns its cache JSON hash" do
283
+ d = Darticle.get(1)
284
+ d.expects(:rand).returns(5)
285
+ assert_equal_hashes({
286
+ :id => 1,
287
+ :title => "Behold! It's CachedRecord!",
288
+ :content => "Cache ORM instances to avoid database queries",
289
+ :@array => [5]
290
+ }, d.as_cache_json)
291
+ end
292
+ it "can be stored in the cache store" do
293
+ Darticle.any_instance.expects(:rand).returns(4)
294
+ Darticle.cached(1)
295
+ assert_equal_hashes({
296
+ :id => 1,
297
+ :title => "Behold! It's CachedRecord!",
298
+ :content => "Cache ORM instances to avoid database queries",
299
+ :@array => [4]
300
+ }.to_json, @redis.get("unit.orm.test_data_mapper.darticle.1"))
301
+ end
302
+ it "can be fetched from the cache store" do
303
+ Darticle.expects(:get).never
304
+ @redis.set(
305
+ "unit.orm.test_data_mapper.darticle.1", {
306
+ :id => 1,
307
+ :title => "Behold! It's CachedRecord!",
308
+ :content => "Cache ORM instances to avoid database queries",
309
+ :@array => [3]
310
+ }.to_json
311
+ )
312
+ assert_equal_hashes({
313
+ :id => 1,
314
+ :title => "Behold! It's CachedRecord!",
315
+ :content => "Cache ORM instances to avoid database queries"
316
+ }, Darticle.cached(1).attributes)
317
+ assert_equal(
318
+ true, Darticle.cached(1).instance_variables.include?(:@array)
319
+ )
320
+ assert_equal([
321
+ 3
322
+ ], Darticle.cached(1).instance_variable_get(:@array))
323
+ end
324
+ end
325
+
326
+ describe "Earticle" do
327
+ it "returns its cache JSON hash" do
328
+ e = Earticle.get(1)
329
+ e.expects(:rand).returns(5)
330
+ assert_equal_hashes({
331
+ :earticle => {
332
+ :id => 1,
333
+ :title => "Behold! It's CachedRecord!",
334
+ :content => "Cache ORM instances to avoid database queries"
335
+ },
336
+ :array => [5]
337
+ }, e.as_cache_json)
338
+ end
339
+ it "can be stored in the cache store" do
340
+ Earticle.any_instance.expects(:rand).returns(4)
341
+ Earticle.cached(1)
342
+ assert_equal_hashes({
343
+ :earticle => {
344
+ :id => 1,
345
+ :title => "Behold! It's CachedRecord!",
346
+ :content => "Cache ORM instances to avoid database queries"
347
+ },
348
+ :array => [4]
349
+ }, @redis.get("unit.orm.test_data_mapper.earticle.1"))
350
+ end
351
+ it "can be fetched from the cache store" do
352
+ Earticle.expects(:get).never
353
+ @redis.set(
354
+ "unit.orm.test_data_mapper.earticle.1", {
355
+ :earticle => {
356
+ :id => 1,
357
+ :title => "Behold! It's CachedRecord!",
358
+ :content => "Cache ORM instances to avoid database queries"
359
+ },
360
+ :array => [3]
361
+ }.to_json
362
+ )
363
+ assert_equal_hashes({
364
+ :id => 1,
365
+ :title => "Behold! It's CachedRecord!",
366
+ :content => "Cache ORM instances to avoid database queries"
367
+ }, Earticle.cached(1).attributes)
368
+ assert_equal(
369
+ true, Earticle.cached(1).instance_variables.include?(:@array)
370
+ )
371
+ assert_equal([
372
+ 3
373
+ ], Earticle.cached(1).instance_variable_get(:@array))
374
+ end
375
+ it "is not memoized" do
376
+ assert_equal false, (Earticle.cached(1).object_id == Earticle.cached(1).object_id)
377
+ end
378
+ end
379
+
380
+ describe "Farticle" do
381
+ it "can be fetched from the cache store" do
382
+ Farticle.expects(:get).never
383
+ @redis.set(
384
+ "unit.orm.test_data_mapper.farticle.1", {
385
+ :farticle => {
386
+ :id => 1,
387
+ :title => "Behold! It's CachedRecord!",
388
+ :content => "Cache ORM instances to avoid database queries"
389
+ },
390
+ :array => [3]
391
+ }.to_json
392
+ )
393
+ assert_equal_hashes({
394
+ :id => 1,
395
+ :title => "Behold! It's CachedRecord!",
396
+ :content => "Cache ORM instances to avoid database queries"
397
+ }, Farticle.cached(1).attributes)
398
+ assert_equal(
399
+ true, Farticle.cached(1).instance_variables.include?(:@array)
400
+ )
401
+ assert_equal([
402
+ 3
403
+ ], Farticle.cached(1).instance_variable_get(:@array))
404
+ end
405
+ it "is memoized" do
406
+ assert_equal Farticle.cached(1).object_id, Farticle.cached(1).object_id
407
+ assert_equal Farticle.cached(1).object_id, Farticle.cached(1).object_id
408
+ end
409
+ end
410
+
411
+ describe "Garticle" do
412
+ it "returns its cache JSON hash" do
413
+ g = Garticle.get(1)
414
+ assert_equal_hashes({
415
+ :id => 1,
416
+ :title => "Behold! It's CachedRecord!",
417
+ :author_id => 1,
418
+ :_comment_ids => [1, 2],
419
+ :_tag_ids => [1, 2]
420
+ }, g.as_cache_json)
421
+ end
422
+ it "can be stored in the cache store" do
423
+ Garticle.cached(1)
424
+ assert_equal_hashes({
425
+ :id => 1,
426
+ :title => "Behold! It's CachedRecord!",
427
+ :author_id => 1,
428
+ :_comment_ids => [1, 2],
429
+ :_tag_ids => [1, 2]
430
+ }, @redis.get("unit.orm.test_data_mapper.garticle.1"))
431
+ assert_equal_hashes({
432
+ :id => 1,
433
+ :name => "Paul Engel",
434
+ :_foo_id => nil
435
+ }, @memcached.get("unit.orm.test_data_mapper.user.1"))
436
+ assert_equal_hashes({
437
+ :id => 2,
438
+ :name => "Ken Adams",
439
+ :_foo_id => 1
440
+ }, @memcached.get("unit.orm.test_data_mapper.user.2"))
441
+ assert_equal_hashes({
442
+ :id => 1,
443
+ :content => "What a great article! :)",
444
+ :poster_id => 2
445
+ }, @redis.get("unit.orm.test_data_mapper.comment.1"))
446
+ assert_equal_hashes({
447
+ :id => 2,
448
+ :content => "Thanks!",
449
+ :poster_id => 1
450
+ }, @redis.get("unit.orm.test_data_mapper.comment.2"))
451
+ end
452
+ it "can be fetched from the cache store" do
453
+ Garticle.expects(:get).never
454
+ User.expects(:get).never
455
+ Comment.expects(:get).never
456
+ Tag.expects(:get).never
457
+ @redis.set(
458
+ "unit.orm.test_data_mapper.garticle.1", {
459
+ :id => 1,
460
+ :title => "Behold! It's CachedRecord!",
461
+ :author_id => 1,
462
+ :_comment_ids => [1, 2],
463
+ :_tag_ids => [1, 2]
464
+ }.to_json
465
+ )
466
+ @memcached.set(
467
+ "unit.orm.test_data_mapper.user.1", {
468
+ :id => 1,
469
+ :name => "Paul Engel"
470
+ }.to_json
471
+ )
472
+ @memcached.set(
473
+ "unit.orm.test_data_mapper.user.2", {
474
+ :id => 2,
475
+ :name => "Ken Adams"
476
+ }.to_json
477
+ )
478
+ @redis.set(
479
+ "unit.orm.test_data_mapper.comment.1", {
480
+ :id => 1,
481
+ :content => "What a great article! :)",
482
+ :poster_id => 2
483
+ }.to_json
484
+ )
485
+ @redis.set(
486
+ "unit.orm.test_data_mapper.comment.2", {
487
+ :id => 2,
488
+ :content => "Thanks!",
489
+ :poster_id => 1
490
+ }.to_json
491
+ )
492
+ @redis.set(
493
+ "unit.orm.test_data_mapper.tag.1", {
494
+ :id => 1,
495
+ :name => "ruby"
496
+ }.to_json
497
+ )
498
+ @redis.set(
499
+ "unit.orm.test_data_mapper.tag.2", {
500
+ :id => 2,
501
+ :name => "gem"
502
+ }.to_json
503
+ )
504
+ g = Garticle.cached(1)
505
+ assert_equal({
506
+ :id => 1,
507
+ :title => "Behold! It's CachedRecord!",
508
+ :author_id => 1
509
+ }, g.attributes)
510
+ assert_equal({
511
+ :id => 1,
512
+ :name => "Paul Engel"
513
+ }, g.author.attributes)
514
+ assert_equal([{
515
+ :id => 1,
516
+ :name => "ruby"
517
+ }, {
518
+ :id => 2,
519
+ :name => "gem"
520
+ }], g.tags.collect(&:attributes))
521
+ assert_equal([{
522
+ :id => 1,
523
+ :content => "What a great article! :)",
524
+ :article_id => 1,
525
+ :poster_id => 2
526
+ }, {
527
+ :id => 2,
528
+ :content => "Thanks!",
529
+ :article_id => 1,
530
+ :poster_id => 1
531
+ }], g.comments.collect(&:attributes))
532
+ assert_equal([{
533
+ :id => 2,
534
+ :name => "Ken Adams"
535
+ }, {
536
+ :id => 1,
537
+ :name => "Paul Engel"
538
+ }], g.comments.collect{|x| x.poster.attributes})
539
+ assert_equal g.author.object_id, g.comments[1].poster.object_id
540
+ end
541
+ end
542
+
543
+ describe "Harticle" do
544
+ it "has the expected as cache options" do
545
+ assert_equal_hashes({
546
+ :store => :redis,
547
+ :expire => 2.seconds,
548
+ :as_json => {:only => [:title]},
549
+ :memoize => true
550
+ }, Harticle.as_cache)
551
+ end
552
+ it "expires after 2 seconds" do
553
+ object_id = Harticle.cached(1).object_id
554
+ assert_equal object_id, Harticle.cached(1).object_id
555
+ assert_equal object_id, Harticle.cached(1).object_id
556
+ sleep 1
557
+ assert_equal object_id, Harticle.cached(1).object_id
558
+ assert_equal object_id, Harticle.cached(1).object_id
559
+ sleep 1.5
560
+ assert_equal false, object_id == Harticle.cached(1).object_id
561
+ end
562
+ end
563
+
564
+ describe "Jarticle" do
565
+ it "has the expected as cache options" do
566
+ assert_equal_hashes({
567
+ :store => :redis,
568
+ :as_json => {:only => [:title]},
569
+ :memoize => true,
570
+ :retain => 4.seconds
571
+ }, Jarticle.as_cache)
572
+ end
573
+ it "does not hit the cache for 4 seconds" do
574
+ object_id = Jarticle.cached(1).object_id
575
+ cached = CachedRecord::Cache.send(:stores)[:redis].get Jarticle.cache_key(1)
576
+
577
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).never
578
+ assert_equal object_id, Jarticle.cached(1).object_id
579
+ sleep 1
580
+ assert_equal object_id, Jarticle.cached(1).object_id
581
+ sleep 1
582
+ assert_equal object_id, Jarticle.cached(1).object_id
583
+ sleep 1
584
+ assert_equal object_id, Jarticle.cached(1).object_id
585
+
586
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).returns(cached)
587
+ sleep 1.5
588
+ assert_equal object_id, Jarticle.cached(1).object_id
589
+
590
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).never
591
+ assert_equal object_id, Jarticle.cached(1).object_id
592
+ sleep 1
593
+ assert_equal object_id, Jarticle.cached(1).object_id
594
+ sleep 1
595
+ assert_equal object_id, Jarticle.cached(1).object_id
596
+ sleep 1
597
+ assert_equal object_id, Jarticle.cached(1).object_id
598
+
599
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).returns(cached)
600
+ sleep 1
601
+ assert_equal object_id, Jarticle.cached(1).object_id
602
+
603
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).never
604
+ assert_equal object_id, Jarticle.cached(1).object_id
605
+
606
+ CachedRecord::Cache.expire Jarticle.cached(1)
607
+ CachedRecord::Cache.send(:stores)[:redis].expects(:get).returns(cached)
608
+ assert_equal false, object_id == Jarticle.cached(1).object_id
609
+ end
610
+ end
611
+ end
612
+ end
613
+
614
+ end
615
+ end
616
+ end