frivol 0.3.1 → 0.4.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.
@@ -5,18 +5,19 @@ class Redis
5
5
  @storage = {}
6
6
  @expires = Hash.new(nil)
7
7
  @version = config[:version] || "2.2.0"
8
+ @results = []
8
9
  end
9
10
 
10
- def [](key)
11
- # puts "retrieve #{key} => #{@storage[key]} (#{(!@expires[key].nil? && @expires[key] < Time.now) ? 'expired' : 'alive'})"
12
- return nil if !@expires[key].nil? && @expires[key] < Time.now
13
- @storage[key]
11
+ def get(key)
12
+ result = expired?(key) ? nil : @storage[key]
13
+ @results << result
14
+ result
14
15
  end
15
16
 
16
- def []=(key, value)
17
- # puts "store #{key} => #{value}"
17
+ def set(key, value)
18
18
  @storage[key] = value
19
19
  @expires.delete key
20
+ @results << 'OK'
20
21
  end
21
22
 
22
23
  def info(key)
@@ -24,33 +25,38 @@ class Redis
24
25
  end
25
26
 
26
27
  def del(key)
27
- # puts "del #{key}"
28
28
  @storage.delete key
29
29
  @expires.delete key
30
+ @results << 1
31
+ 1
30
32
  end
31
33
 
32
34
  def incr(key)
33
- # puts "incr #{key}"
34
35
  @storage[key] ||= 0
35
- @storage[key] += 1
36
+ result = @storage[key] += 1
37
+ @results << result
38
+ result
36
39
  end
37
40
 
38
41
  def incrby(key, amount)
39
- # puts "incr #{key}"
40
42
  @storage[key] ||= 0
41
- @storage[key] += amount
43
+ result = @storage[key] += amount
44
+ @results << result
45
+ result
42
46
  end
43
47
 
44
48
  def decr(key)
45
- # puts "decr #{key}"
46
49
  @storage[key] ||= 0
47
- @storage[key] -= 1
50
+ result = @storage[key] -= 1
51
+ @results << result
52
+ result
48
53
  end
49
54
 
50
55
  def decrby(key, amount)
51
- # puts "decr #{key}"
52
56
  @storage[key] ||= 0
53
- @storage[key] -= amount
57
+ result = @storage[key] -= amount
58
+ @results << result
59
+ result
54
60
  end
55
61
 
56
62
  def expire(key, time)
@@ -60,24 +66,38 @@ class Redis
60
66
  raise RuntimeError.new("-ERR value is not an integer")
61
67
  end
62
68
  @expires[key] = Time.now + t
69
+ @results << 1
70
+ 1
63
71
  end
64
72
 
65
73
  def exists(key)
66
- @storage.key? key
74
+ result = @storage.key?(key) && !expired?(key)
75
+ @results << result
76
+ result
67
77
  end
68
78
 
69
79
  def ttl(key)
70
- # puts "ttl #{key}"
71
- return -1 if @expires[key].nil? || @expires[key] < Time.now
72
- (@expires[key] - Time.now).to_i
80
+ result = if expired?(key)
81
+ -2
82
+ elsif @expires[key].nil?
83
+ -1
84
+ else
85
+ (@expires[key] - Time.now).to_i
86
+ end
87
+ @results << result
88
+ result
73
89
  end
74
90
 
75
91
  def multi(&block)
92
+ @results = []
76
93
  yield(self)
94
+ @results
77
95
  end
78
96
 
79
97
  def flushdb
80
98
  @storage = {}
99
+ @results << 'OK'
100
+ 'OK'
81
101
  end
82
102
 
83
103
  # Help with debugging
@@ -92,4 +112,9 @@ class Redis
92
112
  def method_missing(meth, *args, &block)
93
113
  puts "Missing method: #{meth} called with #{args.inspect}"
94
114
  end
115
+
116
+ private
117
+ def expired?(key)
118
+ !@expires[key].nil? && @expires[key] < Time.now
119
+ end
95
120
  end
@@ -7,14 +7,110 @@ require 'frivol'
7
7
 
8
8
  class Test::Unit::TestCase
9
9
  def setup
10
- fake_redis # Comment out this line to test against a real live Redis
11
- Frivol::Config.redis_config = { :db => 10 } # This will connect to a default Redis setup, otherwise set to { :host => "localhost", :port => 6379 }, for example
12
- Frivol::Config.redis.flushdb
10
+ case ENV['backend']
11
+ when 'redis'
12
+ require 'frivol/backend/redis'
13
+ @backend = Frivol::Backend::Redis.new(:db => 10)
14
+ @backend.flushdb
15
+ Frivol::Config.backend = @backend
16
+ when 'redis_distributed'
17
+ require 'frivol/backend/redis_distributed'
18
+ @backend = Frivol::Backend::RedisDistributed.new([{:db => 11}, {:db => 12}])
19
+ @backend.flushdb
20
+ Frivol::Config.backend = @backend
21
+ when 'riak'
22
+ require 'frivol/backend/riak'
23
+ I18n.enforce_available_locales = false
24
+ Riak.disable_list_keys_warnings = true
25
+ @backend = Frivol::Backend::Riak.new(:nodes => [ { :host => '127.0.0.1' } ])
26
+ @backend.flushdb
27
+ Frivol::Config.backend = @backend
28
+ when 'multi'
29
+ require 'frivol/backend/redis'
30
+ fake_redis
31
+ require 'frivol/backend/multi'
32
+ @old_backend = Frivol::Backend::Redis.new(:db => 10)
33
+ @new_backend = Frivol::Backend::Redis.new(:db => 11)
34
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
35
+ @backend.flushdb
36
+ Frivol::Config.backend = @backend
37
+ when 'multi_redis_redis'
38
+ require 'frivol/backend/redis'
39
+ require 'frivol/backend/multi'
40
+ @old_backend = Frivol::Backend::Redis.new(:db => 10)
41
+ @new_backend = Frivol::Backend::Redis.new(:db => 11)
42
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
43
+ @backend.flushdb
44
+ Frivol::Config.backend = @backend
45
+ when 'multi_redis_redis_distributed'
46
+ require 'frivol/backend/redis'
47
+ require 'frivol/backend/redis_distributed'
48
+ require 'frivol/backend/multi'
49
+ @old_backend = Frivol::Backend::Redis.new(:db => 10)
50
+ @new_backend = Frivol::Backend::RedisDistributed.new(["redis://127.0.0.1:6379/11", "redis://127.0.0.1:6379/12"])
51
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
52
+ @backend.flushdb
53
+ Frivol::Config.backend = @backend
54
+ when 'multi_redis_riak'
55
+ require 'frivol/backend/redis'
56
+ require 'frivol/backend/riak'
57
+ require 'frivol/backend/multi'
58
+ I18n.enforce_available_locales = false
59
+ Riak.disable_list_keys_warnings = true
60
+ @old_backend = Frivol::Backend::Redis.new(:db => 10)
61
+ @new_backend = Frivol::Backend::Riak.new(:nodes => [ { :host => '127.0.0.1' } ])
62
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
63
+ @backend.flushdb
64
+ Frivol::Config.backend = @backend
65
+ when 'multi_redis_distributed_riak'
66
+ require 'frivol/backend/redis'
67
+ require 'frivol/backend/redis_distributed'
68
+ require 'frivol/backend/riak'
69
+ require 'frivol/backend/multi'
70
+ I18n.enforce_available_locales = false
71
+ Riak.disable_list_keys_warnings = true
72
+ @old_backend = Frivol::Backend::RedisDistributed.new(["redis://127.0.0.1:6379/11", "redis://127.0.0.1:6379/12"])
73
+ @new_backend = Frivol::Backend::Riak.new(:nodes => [ { :host => '127.0.0.1' } ])
74
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
75
+ @backend.flushdb
76
+ Frivol::Config.backend = @backend
77
+ when 'multi_riak_redis'
78
+ require 'frivol/backend/riak'
79
+ require 'frivol/backend/redis'
80
+ require 'frivol/backend/multi'
81
+ I18n.enforce_available_locales = false
82
+ Riak.disable_list_keys_warnings = true
83
+ @old_backend = Frivol::Backend::Riak.new(:nodes => [ { :host => '127.0.0.1' } ])
84
+ @new_backend = Frivol::Backend::Redis.new(:db => 10)
85
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
86
+ @backend.flushdb
87
+ Frivol::Config.backend = @backend
88
+ when 'multi_riak_redis_distributed'
89
+ require 'frivol/backend/riak'
90
+ require 'frivol/backend/redis'
91
+ require 'frivol/backend/redis_distributed'
92
+ require 'frivol/backend/multi'
93
+ I18n.enforce_available_locales = false
94
+ Riak.disable_list_keys_warnings = true
95
+ @old_backend = Frivol::Backend::Riak.new(:nodes => [ { :host => '127.0.0.1' } ])
96
+ @new_backend = Frivol::Backend::RedisDistributed.new(["redis://127.0.0.1:6379/11", "redis://127.0.0.1:6379/12"])
97
+ @backend = Frivol::Backend::Multi.new([ @new_backend, @old_backend ])
98
+ @backend.flushdb
99
+ Frivol::Config.backend = @backend
100
+ else
101
+ require 'frivol/backend/redis'
102
+ fake_redis
103
+ @backend = Frivol::Backend::Redis.new(:db => 10)
104
+ @backend.flushdb
105
+ Frivol::Config.backend = @backend
106
+ end
107
+ # NOTE: Because some backends like Riak are eventually consistent,
108
+ # we're changing the id of the test class per test.
109
+ @test_id = TestClass.incr_id
13
110
  end
14
111
 
15
112
  def teardown
16
- # puts Frivol::Config.redis.inspect
17
- Frivol::Config.redis.flushdb
113
+ @backend.flushdb
18
114
  end
19
115
 
20
116
  def fake_redis
@@ -24,12 +120,26 @@ class Test::Unit::TestCase
24
120
  def ruby_one_eight?
25
121
  @ruby_one_eight || `ruby -v`.include?('1.8')
26
122
  end
123
+
124
+ def self.multi_test?
125
+ ENV['backend'].to_s.start_with?('multi')
126
+ end
127
+
128
+ def self.riak_test?
129
+ ENV['backend'].to_s.include?('riak')
130
+ end
27
131
  end
28
132
 
29
133
  class TestClass
30
134
  include Frivol
31
135
 
136
+ @@id = 1
137
+
138
+ def self.incr_id
139
+ @@id += 1
140
+ end
141
+
32
142
  def id
33
- 1
143
+ @@id
34
144
  end
35
145
  end
@@ -0,0 +1,33 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestBackends < Test::Unit::TestCase
4
+ def test_ttl
5
+ t = TestClass.new
6
+ assert_nil @backend.ttl(t.storage_key)
7
+
8
+ t.store :something => 'somewhere'
9
+ assert_nil @backend.ttl(t.storage_key)
10
+
11
+ t.expire_storage 10
12
+ assert_in_delta 10, @backend.ttl(t.storage_key), 2
13
+ end
14
+
15
+ def test_exists
16
+ t = TestClass.new
17
+ refute @backend.exists(t.storage_key)
18
+
19
+ t.store :something => 'somewhere'
20
+ assert @backend.exists(t.storage_key)
21
+
22
+ t.delete_storage
23
+ refute @backend.exists(t.storage_key)
24
+ end
25
+
26
+ def test_exists_with_expiry
27
+ t = Class.new(TestClass) { storage_expires_in -1 }.new
28
+ refute @backend.exists(t.storage_key)
29
+
30
+ t.store :something => 'somewhere'
31
+ refute @backend.exists(t.storage_key)
32
+ end
33
+ end
@@ -69,4 +69,35 @@ class TestCounters < Test::Unit::TestCase
69
69
  t.store_yellow 10
70
70
  assert_equal 0, t.retrieve_yellow(0)
71
71
  end
72
+
73
+ def test_expire_on_a_counter_bucket_using_increment
74
+ t = Class.new(TestClass) { storage_bucket :fuscia, :counter => true, :expires_in => -1 }.new
75
+ assert_equal 1, t.increment_fuscia
76
+ assert_equal 0, t.retrieve_fuscia(0)
77
+ end
78
+
79
+ def test_expire_on_a_counter_bucket_using_increment_by
80
+ t = Class.new(TestClass) { storage_bucket :magenta, :counter => true, :expires_in => -1 }.new
81
+ t.increment_magenta_by 10
82
+ assert_equal 0, t.retrieve_magenta(0)
83
+ end
84
+
85
+ def test_expire_on_a_counter_bucket_using_decrement
86
+ t = Class.new(TestClass) { storage_bucket :rose, :counter => true, :expires_in => -1 }.new
87
+ t.decrement_rose
88
+ assert_equal 0, t.retrieve_rose(0)
89
+ end
90
+
91
+ def test_expire_on_a_counter_bucket_using_decrement_by
92
+ t = Class.new(TestClass) { storage_bucket :orchid, :counter => true, :expires_in => -1 }.new
93
+ t.decrement_orchid_by 10
94
+ assert_equal 0, t.retrieve_orchid(0)
95
+ end
96
+
97
+ def test_delete_a_counter_bucket
98
+ t = Class.new(TestClass) { storage_bucket :debt, :counter => true }.new
99
+ t.store_debt 100_000
100
+ t.delete_debt
101
+ assert_equal 0, t.retrieve_debt(0)
102
+ end
72
103
  end
@@ -3,7 +3,7 @@ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
3
3
  class TestFrivol < Test::Unit::TestCase
4
4
  def test_have_a_default_storage_key_made_up_of_the_class_name_and_id
5
5
  t = TestClass.new
6
- assert_equal "TestClass-1", t.storage_key
6
+ assert_equal "TestClass-#{@test_id}", t.storage_key
7
7
  end
8
8
 
9
9
  def test_store_and_retrieve_data
@@ -12,11 +12,27 @@ class TestFrivol < Test::Unit::TestCase
12
12
  assert_equal "value", t.retrieve(:value => 'default')
13
13
  end
14
14
 
15
+ def test_retrieve_non_existing
16
+ t = TestClass.new
17
+ assert_nothing_raised do
18
+ assert_nil t.retrieve(:nothing => nil)
19
+ end
20
+ end
21
+
15
22
  def test_return_a_default_for_a_value_thats_not_in_storage
16
23
  t = TestClass.new
17
24
  assert_equal "default", t.retrieve(:value => 'default')
18
25
  end
19
26
 
27
+ def test_return_default_when_stored_value_is_emtpy_string
28
+ t = TestClass.new
29
+ key = t.storage_key
30
+ Frivol::Config.backend.set(key, "")
31
+ assert_nothing_raised do
32
+ assert_equal "36", t.retrieve( :some_string => "36")
33
+ end
34
+ end
35
+
20
36
  def test_save_and_retrieve_multiple_values
21
37
  t = TestClass.new
22
38
  t.store :val1 => 1, :val2 => 2
@@ -68,7 +84,7 @@ class TestFrivol < Test::Unit::TestCase
68
84
  end.new
69
85
 
70
86
  t.store :value => 'value'
71
- assert Frivol::Config.redis["my_storage"]
87
+ assert @backend.get("my_storage")
72
88
  end
73
89
 
74
90
  def test_retain_Times_as_Times
@@ -87,7 +103,7 @@ class TestFrivol < Test::Unit::TestCase
87
103
  end
88
104
 
89
105
  def test_use_default_expiry_set_on_the_class
90
- klass = Class.new(TestClass) { storage_expires_in -1 }
106
+ klass = Class.new(TestClass) { storage_expires_in -10 }
91
107
  t = klass.new
92
108
  t.store :value => 'value'
93
109
 
@@ -101,10 +117,10 @@ class TestFrivol < Test::Unit::TestCase
101
117
  t = Class.new(TestClass) { storage_expires_in 2 }.new
102
118
 
103
119
  t.store :value => 'value'
104
- assert Frivol::Config.redis.ttl(t.storage_key) > 0
120
+ assert @backend.ttl(t.storage_key) > 0
105
121
 
106
122
  t.store :value => 'value' # a second time
107
- assert Frivol::Config.redis.ttl(t.storage_key) > 0
123
+ assert @backend.ttl(t.storage_key) > 0
108
124
  end
109
125
 
110
126
  def test_be_able_to_include_in_other_classes_with_storage_expiry
@@ -119,8 +135,8 @@ class TestFrivol < Test::Unit::TestCase
119
135
  t = TestClass.new
120
136
  t.retrieve :value => 'default'
121
137
 
122
- redis = Frivol::Config.redis
123
- def redis.[](key); raise 'Onoes, loaded again'; end
138
+ # ensure we're getting the result from the cache and not Redis
139
+ def @backend.get(key); raise 'Onoes, loaded again'; end
124
140
 
125
141
  t.retrieve :value => 'default'
126
142
  end
@@ -141,8 +157,7 @@ class TestFrivol < Test::Unit::TestCase
141
157
  t.clear_gold
142
158
 
143
159
  # ensure we're getting the result from Redis and not the cache
144
- redis = Frivol::Config.redis
145
- def redis.[](key)
160
+ def @backend.get(key, expiry = nil)
146
161
  MultiJson.dump(:value => 'this is what we want')
147
162
  end
148
163
 
@@ -33,18 +33,18 @@ class TestFrivolize < Test::Unit::TestCase
33
33
  @@count = 0
34
34
 
35
35
  # Imagine counting dinosuars takes a long time, what with the need to invent a time machine first and all
36
- def dinosaur_count
36
+ def dinosaurus_count
37
37
  @@count += 1
38
38
  end
39
- frivolize :dinosaur_count, { :bucket => :dinosaurs, :expires_in => -1 }
39
+ frivolize :dinosaurus_count, { :bucket => :dinosauruss, :expires_in => -1 }
40
40
  end
41
41
 
42
42
  t = klass.new
43
- assert_equal 1, t.dinosaur_count
44
- assert_equal 1, t.dinosaur_count # Still 10 because it's coming from the class cache
43
+ assert_equal 1, t.dinosaurus_count
44
+ assert_equal 1, t.dinosaurus_count # Still 1 because it's coming from the class cache
45
45
 
46
46
  t = klass.new
47
- assert_equal 2, t.dinosaur_count
47
+ assert_equal 2, t.dinosaurus_count
48
48
  end
49
49
 
50
50
  def test_frivolize_methods_with_expiry_as_a_counter
@@ -53,19 +53,19 @@ class TestFrivolize < Test::Unit::TestCase
53
53
  @@count = 0
54
54
 
55
55
  # Imagine counting dinosuars takes a long time, what with the need to invent a time machine first and all
56
- def dinosaur_count
56
+ def dinosaurii_count
57
57
  @@count += 1
58
58
  end
59
- frivolize :dinosaur_count, { :expires_in => -1, :counter => true }
59
+ frivolize :dinosaurii_count, { :expires_in => -1, :counter => true }
60
60
  end
61
61
 
62
62
  t = klass.new
63
- assert t.methods.include?(ruby_one_eight? ? 'store_dinosaur_count' : :store_dinosaur_count) # check that the bucket name is the method name
63
+ assert t.methods.include?(ruby_one_eight? ? 'store_dinosaurii_count' : :store_dinosaurii_count) # check that the bucket name is the method name
64
64
 
65
- assert_equal 1, t.dinosaur_count
65
+ assert_equal 1, t.dinosaurii_count
66
66
 
67
67
  t = klass.new # a fresh instance after value expired
68
- assert_equal 2, t.dinosaur_count
68
+ assert_equal 2, t.dinosaurii_count
69
69
  end
70
70
 
71
71
  def test_frivolize_with_seed_as_a_counter_for_increment
@@ -73,7 +73,7 @@ class TestFrivolize < Test::Unit::TestCase
73
73
  def bak_baks
74
74
  88_888
75
75
  end
76
- frivolize :bak_baks, :counter => true, :seed => Proc.new{ |obj| obj.bak_baks}
76
+ frivolize :bak_baks, :counter => true, :seed => Proc.new{ |obj| obj.bak_baks }
77
77
  end.new
78
78
 
79
79
  assert_equal 88_888 + 1, t.increment_bak_baks