frivol 0.2.0 → 0.3.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.
@@ -1,445 +1,153 @@
1
1
  require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
2
 
3
3
  class TestFrivol < Test::Unit::TestCase
4
- def setup
5
- fake_redis # Comment out this line to test against a real live Redis
6
- Frivol::Config.redis_config = { :thread_safe => true } # This will connect to a default Redis setup, otherwise set to { :host => "localhost", :port => 6379 }, for example
7
- Frivol::Config.redis.flushdb
8
- end
9
-
10
- def teardown
11
- # puts Frivol::Config.redis.inspect
12
- Frivol::Config.redis.flushdb
13
- end
14
-
15
- should "have a default storage key made up of the class name and id" do
4
+ def test_have_a_default_storage_key_made_up_of_the_class_name_and_id
16
5
  t = TestClass.new
17
6
  assert_equal "TestClass-1", t.storage_key
18
7
  end
19
-
20
- should "store and retrieve data" do
8
+
9
+ def test_store_and_retrieve_data
21
10
  t = TestClass.new
22
- t.save
23
- assert_equal "value", t.load
11
+ t.store :value => 'value'
12
+ assert_equal "value", t.retrieve(:value => 'default')
24
13
  end
25
-
26
- should "return a default for a value that's not in storage" do
14
+
15
+ def test_return_a_default_for_a_value_thats_not_in_storage
27
16
  t = TestClass.new
28
- assert_equal "default", t.load
17
+ assert_equal "default", t.retrieve(:value => 'default')
29
18
  end
30
-
31
- should "save and retrieve multiple values" do
32
- class MultiTestClass < TestClass
33
- def save
34
- store :val1 => 1, :val2 => 2
35
- end
36
-
37
- def load
38
- retrieve :val1 => nil, :val2 => nil
39
- end
19
+
20
+ def test_save_and_retrieve_multiple_values
21
+ t = TestClass.new
22
+ t.store :val1 => 1, :val2 => 2
23
+
24
+ r = t.retrieve :val1 => nil, :val2 => nil
25
+ if ruby_one_eight?
26
+ assert r == [ 1, 2 ] || r == [ 2, 1 ] # yuck!
27
+ else
28
+ # Ruby 1.8 may fail this because hash keys do not guarantee order
29
+ assert_equal [ 1, 2 ], r
40
30
  end
41
-
42
- t = MultiTestClass.new
43
- t.save
44
- assert_equal [ 1, 2 ], t.load
45
31
  end
46
-
47
- should "get defaults from instance methods if defined" do
48
- class DefaultsTestClass < TestClass
49
- def load
50
- retrieve :value => nil, :value2 => :value2_default
51
- end
52
-
32
+
33
+ def test_get_defaults_from_instance_methods_if_defined
34
+ t = Class.new(TestClass) do
53
35
  def value2_default
54
36
  "value2"
55
37
  end
56
- end
57
-
58
- t = DefaultsTestClass.new
59
- t.save
60
- assert_equal [ "value", "value2" ], t.load.sort
38
+ end.new
39
+
40
+ result = t.retrieve :value => nil, :value2 => :value2_default
41
+ assert_equal [ "", "value2" ], result.map(&:to_s).sort
61
42
  end
62
-
63
- should "not be naughty and try to respond to nil default" do
64
- class DefaultNilTestClass < TestClass
65
- def load
66
- retrieve :value => nil
67
- end
68
- end
69
-
70
- t = DefaultNilTestClass.new
71
- assert_equal nil, t.load
43
+
44
+ def test_not_be_naughty_and_try_to_respond_to_nil_default
45
+ t = TestClass.new
46
+ assert_equal nil, t.retrieve(:value => nil)
72
47
  end
73
48
 
74
- should "only try respond to symbol defaults" do
75
- class DefaultNonSymbolTestClass < TestClass
49
+ def test_only_try_respond_to_symbol_defaults
50
+ t = Class.new(TestClass) do
76
51
  def load
77
52
  retrieve :value => "load", :def_val => :default_value # yes, that's right, we would cause a stack overflow here
78
53
  end
79
-
54
+
80
55
  def default_value
81
56
  "yay!"
82
57
  end
83
- end
84
-
85
- t = DefaultNonSymbolTestClass.new
58
+ end.new
59
+
86
60
  assert_equal [ "load", "yay!" ], t.load.sort
87
61
  end
88
62
 
89
- should "be able to override the key method" do
90
- class OverrideKeyTestClass < TestClass
63
+ def test_be_able_to_override_the_key_method
64
+ t = Class.new(TestClass) do
91
65
  def storage_key(bucket = nil)
92
66
  "my_storage"
93
67
  end
94
- end
95
-
96
- t = OverrideKeyTestClass.new
97
- t.save
98
- assert_equal "value", t.load
68
+ end.new
69
+
70
+ t.store :value => 'value'
99
71
  assert Frivol::Config.redis["my_storage"]
100
72
  end
101
-
102
- should "retain Times as Times" do
103
- class TimeTestClass < TestClass
104
- def save
105
- store :t => Time.local(2010, 8, 20)
106
- end
107
-
108
- def load
109
- retrieve :t => nil
110
- end
111
- end
112
-
113
- t = TimeTestClass.new
114
- t.save
115
- assert_equal Time.local(2010, 8, 20), t.load
116
- end
117
-
118
- should "expire storage the everytime time it's stored" do
119
- class ExpiryTestClass < TestClass
120
- storage_expires_in 60
121
- end
122
-
123
- Frivol::Config.redis.expects(:expire).twice
124
- Frivol::Config.redis.expects(:ttl).once
125
- t = ExpiryTestClass.new
126
- t.load
127
- t.save
128
- t = ExpiryTestClass.new # get a new one
129
- t.save
73
+
74
+ def test_retain_Times_as_Times
75
+ t = TestClass.new
76
+ t.store :t => Time.local(2010, 8, 20)
77
+ assert_equal Time.local(2010, 8, 20), t.retrieve(:t => nil)
130
78
  end
131
-
132
- should "expires should not throw nasty errors" do
79
+
80
+ def test_expires_should_not_throw_nasty_errors
133
81
  t = TestClass.new
134
- t.save
135
- t.expire_storage 1
136
- sleep 2
82
+ t.store :value => 'value'
83
+ t.expire_storage -1
84
+
137
85
  t = TestClass.new # Get a fresh instance so that the @frivol_data is empty
138
- assert_equal "default", t.load
86
+ assert_equal "default", t.retrieve(:value => 'default')
139
87
  end
140
-
141
- should "use default expiry set on the class" do
142
- class ExpiryTestClass < TestClass
143
- storage_expires_in 1
144
- end
145
- t = ExpiryTestClass.new
146
- t.save
147
- sleep 2
148
- t = ExpiryTestClass.new # Get a fresh instance so that the @frivol_data is empty
149
- assert_equal "default", t.load
88
+
89
+ def test_use_default_expiry_set_on_the_class
90
+ klass = Class.new(TestClass) { storage_expires_in -1 }
91
+ t = klass.new
92
+ t.store :value => 'value'
93
+
94
+ t = klass.new # Get a fresh instance so that the @frivol_data is empty
95
+ assert_equal "default", t.retrieve(:value => 'default')
150
96
  end
151
97
 
152
- # If you save a value to a volatile key, the expiry is cleared
153
- should "resaving a value should not clear the expiry" do
154
- class ResavingExpiryTestClass < TestClass
155
- storage_expires_in 2
156
- end
157
- t = ResavingExpiryTestClass.new
158
- t.save
98
+ # In older versions of Redis, if you save a value to a volatile key, the expiry is cleared
99
+ # TODO: test against older Redis and remove re-expiring for versions that don't need it
100
+ def test_resaving_a_value_should_not_clear_the_expiry
101
+ t = Class.new(TestClass) { storage_expires_in 2 }.new
102
+
103
+ t.store :value => 'value'
159
104
  assert Frivol::Config.redis.ttl(t.storage_key) > 0
160
- t.save # a second time
105
+
106
+ t.store :value => 'value' # a second time
161
107
  assert Frivol::Config.redis.ttl(t.storage_key) > 0
162
108
  end
163
-
164
- should "be able to include in other classes with storage expiry" do
165
- class BlankTestClass
166
- end
167
- Frivol::Config.include_in(BlankTestClass, 30)
168
- t = BlankTestClass.new
109
+
110
+ def test_be_able_to_include_in_other_classes_with_storage_expiry
111
+ klass = Class.new
112
+ Frivol::Config.include_in(klass, 30)
113
+ t = klass.new
169
114
  assert t.respond_to? :store
170
- assert_equal 30, BlankTestClass.storage_expiry
171
- end
172
-
173
- should "return the already loaded hash if it's already loaded" do
174
- Frivol::Config.redis.expects(:[]).once
175
- t = TestClass.new
176
- t.load
177
- t.load
115
+ assert_equal 30, klass.storage_expiry
178
116
  end
179
-
180
- should "be able to delete storage" do
117
+
118
+ def test_return_the_already_loaded_hash_if_its_already_loaded
181
119
  t = TestClass.new
182
- t.save
183
- t.delete_storage
184
- assert_equal "default", t.load
185
- end
186
-
187
- should "be able to create and use buckets" do
188
- class SimpleBucketTestClass < TestClass
189
- storage_bucket :blue
190
- end
191
- t = SimpleBucketTestClass.new
192
- assert t.respond_to?(:store_blue)
193
- assert t.respond_to?(:retrieve_blue)
194
- end
195
-
196
- should "store different values in different buckets" do
197
- class StorageBucketTestClass < TestClass
198
- storage_bucket :blue
199
-
200
- def save_blue
201
- store_blue :value => "blue value"
202
- end
203
-
204
- def load_blue
205
- retrieve_blue :value => "blue default"
206
- end
207
- end
208
- t = StorageBucketTestClass.new
209
- t.save
210
- t.save_blue
211
- assert_equal "value", t.load
212
- assert_equal "blue value", t.load_blue
213
- end
120
+ t.retrieve :value => 'default'
214
121
 
215
- should "have different expiry times for different buckets" do
216
- class ExpireBucketsTestClass < TestClass
217
- storage_bucket :blue, :expires_in => 1
218
- storage_expires_in 2
219
- end
220
- t = ExpireBucketsTestClass.new
221
- assert_equal 1, ExpireBucketsTestClass.storage_expiry(:blue)
222
- assert_equal 2, ExpireBucketsTestClass.storage_expiry
223
- end
122
+ redis = Frivol::Config.redis
123
+ def redis.[](key); raise 'Onoes, loaded again'; end
224
124
 
225
- should "expire data in buckets" do
226
- class ExpireBucketsTestClass < TestClass
227
- storage_bucket :blue, :expires_in => 1
228
- storage_expires_in 3
229
-
230
- def save_blue
231
- store_blue :value => "blue value"
232
- end
233
-
234
- def load_blue
235
- retrieve_blue :value => "blue default"
236
- end
237
- end
238
- t = ExpireBucketsTestClass.new
239
- t.save
240
- t.save_blue
241
- sleep 2
242
- t = ExpireBucketsTestClass.new # get a new instance so @frivol_data is empty
243
- assert_equal "value", t.load
244
- assert_equal "blue default", t.load_blue
245
- end
246
-
247
- should "be able to create counter buckets" do
248
- class SimpleCounterTestClass < TestClass
249
- storage_bucket :blue, :counter => true
250
- end
251
- t = SimpleCounterTestClass.new
252
- assert t.respond_to?(:store_blue)
253
- assert t.respond_to?(:retrieve_blue)
254
- assert t.respond_to?(:increment_blue)
125
+ t.retrieve :value => 'default'
255
126
  end
256
-
257
- should "store, increment and retrieve integers in a counter" do
258
- class IncrCounterTestClass < TestClass
259
- storage_bucket :blue, :counter => true
260
-
261
- def save_blue
262
- store_blue 10
263
- end
264
-
265
- def load_blue
266
- retrieve_blue 0
267
- end
268
- end
269
- t = IncrCounterTestClass.new
270
- assert_equal 0, t.load_blue
271
- t.save_blue
272
- assert_equal 10, t.load_blue
273
- assert_equal 11, t.increment_blue
274
- assert_equal 11, t.load_blue
275
- end
276
-
277
- should "set expiry on counters" do
278
- class SetExpireCounterTestClass < TestClass
279
- storage_bucket :sheep_counter, :counter => true, :expires_in => 1
280
- end
281
- t = SetExpireCounterTestClass.new
282
- assert_equal 1, SetExpireCounterTestClass.storage_expiry(:sheep_counter)
283
- end
284
-
285
- should "expire a counter bucket" do
286
- class ExpireCounterTestClass < TestClass
287
- storage_bucket :kitten_grave, :counter => true, :expires_in => 1
288
127
 
289
- def bury_kittens
290
- store_kitten_grave 10
291
- end
292
-
293
- def peek_in_grave
294
- retrieve_kitten_grave 0
295
- end
296
- end
297
-
298
- k = ExpireCounterTestClass.new
299
- k.bury_kittens
300
- assert_equal 10, k.peek_in_grave
301
-
302
- sleep 2
303
- assert_equal 0, k.peek_in_grave
128
+ def test_be_able_to_delete_storage
129
+ t = TestClass.new
130
+ t.store :value => ''
131
+ t.delete_storage
132
+ assert_equal "default", t.retrieve(:value => 'default')
304
133
  end
305
134
 
306
- # Note: this test will fail from time to time using fake_redis because fake_redis is not thread safe
307
- should "have thread safe counters" do
308
- class ThreadCounterTestClass < TestClass
309
- storage_bucket :blue, :counter => true
310
-
311
- def save_blue
312
- store_blue 10
313
- end
314
-
315
- def load_blue
316
- retrieve_blue 0
317
- end
318
- end
319
- t = ThreadCounterTestClass.new
320
- t.save_blue
321
- assert_equal 10, t.load_blue
322
-
323
- threads = []
324
- 100.times do
325
- threads << Thread.new do
326
- 10.times do
327
- temp = ThreadCounterTestClass.new
328
- temp.increment_blue
329
- sleep(rand(10) / 100.0)
330
- end
331
- end
332
- end
333
- threads.each { |a| a.join }
334
-
335
- assert_equal 1010, t.load_blue
336
- end
337
-
338
- should "be able to delete storage for a bucket" do
339
- class DeleteBucketTestClass < TestClass
340
- storage_bucket :silver
341
-
342
- def save_silver
343
- store_silver :value => "value"
344
- end
345
-
346
- def load_silver
347
- retrieve_silver :value => "default"
348
- end
349
- end
350
- t = DeleteBucketTestClass.new
351
- t.save_silver
352
- assert_equal "value", t.load_silver
353
- t.delete_silver
354
- assert_equal "default", t.load_silver
355
- end
356
-
357
- should "be able to clear cached storage for a bucket" do
358
- class ClearBucketTestClass < TestClass
359
- storage_bucket :gold
360
-
361
- def save_gold
362
- store_gold :value => "value"
363
- end
364
-
365
- def load_gold
366
- retrieve_gold :value => "default"
367
- end
368
- end
369
- t = ClearBucketTestClass.new
370
- t.save_gold
371
- assert_equal "value", t.load_gold
372
- t.clear_gold
373
- # ensure we're getting the result from Redis and not the cache
374
- Frivol::Config.redis.expects(:[]).with(t.storage_key(:gold)).once.returns({ :value => "value" }.to_json)
375
- assert_equal "value", t.load_gold
376
- end
377
-
378
- should "frivolize methods" do
379
- class FrivolizeTestClass < TestClass
380
- def dinosaur_count
381
- 10
382
- end
383
- frivolize :dinosaur_count
384
- end
135
+ def test_be_able_to_clear_cached_storage_for_a_bucket
136
+ t = Class.new(TestClass) { storage_bucket :gold }.new
137
+ t.store_gold :value => "value"
138
+ value = t.retrieve_gold :value => "default"
139
+ assert_equal "value", value
385
140
 
386
- Frivol::Config.redis.expects(:[]=).once
387
- Frivol::Config.redis.expects(:[]).twice.returns(nil, { :dinosaur_count => 10 }.to_json)
141
+ t.clear_gold
388
142
 
389
- t = FrivolizeTestClass.new
390
- assert t.methods.include? "dinosaur_count"
391
- assert t.methods.include? "frivolized_dinosaur_count"
392
-
393
- assert_equal 10, t.dinosaur_count
394
-
395
- t = FrivolizeTestClass.new # a fresh instance
396
- assert_equal 10, t.dinosaur_count
397
- end
398
-
399
- should "frivolize methods with expiry in a bucket" do
400
- class FrivolizeExpiringBucketTestClass < TestClass
401
- def dinosaur_count
402
- 10
403
- end
404
- frivolize :dinosaur_count, { :bucket => :dinosaurs, :expires_in => 1 }
143
+ # ensure we're getting the result from Redis and not the cache
144
+ redis = Frivol::Config.redis
145
+ def redis.[](key)
146
+ MultiJson.dump(:value => 'this is what we want')
405
147
  end
406
- Frivol::Config.redis.expects(:[]=).twice
407
- Frivol::Config.redis.expects(:[]).times(3).returns(nil, { :dinosaur_count => 10 }.to_json, nil)
408
148
 
409
- t = FrivolizeExpiringBucketTestClass.new
410
- assert_equal 10, t.dinosaur_count
411
-
412
- t = FrivolizeExpiringBucketTestClass.new # a fresh instance
413
- assert_equal 10, t.dinosaur_count
414
-
415
- sleep 2
416
-
417
- t = FrivolizeExpiringBucketTestClass.new # another fresh instance after value expired
418
- assert_equal 10, t.dinosaur_count
149
+ value = t.retrieve_gold :value => "default"
150
+ assert_equal "this is what we want", value
419
151
  end
420
-
421
- should "frivolize methods with expiry as a counter" do
422
- class FrivolizeExpiringBucketTestClass < TestClass
423
- def dinosaur_count
424
- 10
425
- end
426
- frivolize :dinosaur_count, { :expires_in => 1, :counter => true }
427
- end
428
- Frivol::Config.redis.expects(:[]=).twice
429
- Frivol::Config.redis.expects(:[]).times(3).returns(nil, 10, nil)
430
-
431
- t = FrivolizeExpiringBucketTestClass.new
432
- assert t.methods.include? "store_dinosaur_count" # check that the bucket name is the method name
433
152
 
434
- assert_equal 10, t.dinosaur_count
435
-
436
- t = FrivolizeExpiringBucketTestClass.new # a fresh instance
437
- assert_equal 10, t.dinosaur_count
438
-
439
- sleep 2
440
-
441
- t = FrivolizeExpiringBucketTestClass.new # another fresh instance after value expired
442
- assert_equal 10, t.dinosaur_count
443
- end
444
-
445
153
  end