jashmenn-dalli 1.0.3

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,34 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+ require 'memcached_mock'
4
+
5
+ class TestEncoding < Test::Unit::TestCase
6
+
7
+ context 'using a live server' do
8
+ should 'support i18n content' do
9
+ memcached do |dc|
10
+ key = 'foo'
11
+ bad_key = utf8 = 'ƒ©åÍÎ'
12
+
13
+ assert dc.set(key, utf8)
14
+ assert_equal utf8, dc.get(key)
15
+
16
+ # keys must be ASCII
17
+ assert_raise ArgumentError, /illegal character/ do
18
+ dc.set(bad_key, utf8)
19
+ end
20
+ end
21
+ end
22
+
23
+ should 'support content expiry' do
24
+ memcached do |dc|
25
+ key = 'foo'
26
+ assert dc.set(key, 'bar', 1)
27
+ assert_equal 'bar', dc.get(key)
28
+ sleep 2
29
+ assert_equal nil, dc.get(key)
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,89 @@
1
+ require 'helper'
2
+
3
+ class TestFailover < Test::Unit::TestCase
4
+ context 'assuming some bad servers' do
5
+ should 'handle graceful failover' do
6
+ memcached(29125) do
7
+ memcached(29126) do
8
+ dc = Dalli::Client.new ['localhost:29125', 'localhost:29126']
9
+ dc.set 'foo', 'bar'
10
+ foo = dc.get 'foo'
11
+ assert foo, 'bar'
12
+
13
+ memcached_kill(29125)
14
+
15
+ dc.set 'foo', 'bar'
16
+ foo = dc.get 'foo'
17
+ assert foo, 'bar'
18
+
19
+ memcached_kill(29126)
20
+
21
+ assert_raise Dalli::RingError, :message => "No server available" do
22
+ dc.set 'foo', 'bar'
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ should 'handle them gracefully in get_multi' do
29
+ memcached(29125) do
30
+ memcached(29126) do
31
+ dc = Dalli::Client.new ['localhost:29125', 'localhost:29126']
32
+ dc.set 'a', 'a1'
33
+ result = dc.get_multi ['a']
34
+ assert_equal result, {'a' => 'a1'}
35
+
36
+ memcached_kill(29125)
37
+
38
+ result = dc.get_multi ['a']
39
+ assert_equal result, {'a' => 'a1'}
40
+ end
41
+ end
42
+ end
43
+
44
+ should 'handle graceful failover in get_multi' do
45
+ memcached(29125) do
46
+ memcached(29126) do
47
+ dc = Dalli::Client.new ['localhost:29125', 'localhost:29126']
48
+ dc.set 'foo', 'foo1'
49
+ dc.set 'bar', 'bar1'
50
+ result = dc.get_multi ['foo', 'bar']
51
+ assert_equal result, {'foo' => 'foo1', 'bar' => 'bar1'}
52
+
53
+ memcached_kill(29125)
54
+
55
+ dc.set 'foo', 'foo1'
56
+ dc.set 'bar', 'bar1'
57
+ result = dc.get_multi ['foo', 'bar']
58
+ assert_equal result, {'foo' => 'foo1', 'bar' => 'bar1'}
59
+
60
+ memcached_kill(29126)
61
+
62
+ assert_raise Dalli::RingError, :message => "No server available" do
63
+ dc.get_multi ['foo', 'bar']
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ should 'stats should still properly report' do
70
+ memcached(29125) do
71
+ memcached(29126) do
72
+ dc = Dalli::Client.new ['localhost:29125', 'localhost:29126']
73
+ result = dc.stats
74
+ assert_instance_of Hash, result['localhost:29125']
75
+ assert_instance_of Hash, result['localhost:29126']
76
+
77
+ memcached_kill(29125)
78
+
79
+ dc = Dalli::Client.new ['localhost:29125', 'localhost:29126']
80
+ result = dc.stats
81
+ assert_instance_of NilClass, result['localhost:29125']
82
+ assert_instance_of Hash, result['localhost:29126']
83
+
84
+ memcached_kill(29126)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,54 @@
1
+ require 'helper'
2
+
3
+ class TestNetwork < Test::Unit::TestCase
4
+
5
+ context 'assuming a bad network' do
6
+
7
+ should 'handle no server available' do
8
+ assert_raise Dalli::RingError, :message => "No server available" do
9
+ dc = Dalli::Client.new 'localhost:19333'
10
+ dc.get 'foo'
11
+ end
12
+ end
13
+
14
+ context 'with a fake server' do
15
+ should 'handle connection reset' do
16
+ memcached_mock(lambda {|sock| sock.close }) do
17
+ assert_raise Dalli::RingError, :message => "No server available" do
18
+ dc = Dalli::Client.new('localhost:19123')
19
+ dc.get('abc')
20
+ end
21
+ end
22
+ end
23
+
24
+ should 'handle malformed response' do
25
+ memcached_mock(lambda {|sock| sock.write('123') }) do
26
+ assert_raise Dalli::RingError, :message => "No server available" do
27
+ dc = Dalli::Client.new('localhost:19123')
28
+ dc.get('abc')
29
+ end
30
+ end
31
+ end
32
+
33
+ should 'handle connect timeouts' do
34
+ memcached_mock(lambda {|sock| sleep(0.6); sock.close }, :delayed_start) do
35
+ assert_raise Dalli::RingError, :message => "No server available" do
36
+ dc = Dalli::Client.new('localhost:19123')
37
+ dc.get('abc')
38
+ end
39
+ end
40
+ end
41
+
42
+ should 'handle read timeouts' do
43
+ memcached_mock(lambda {|sock| sleep(0.6); sock.write('giraffe') }) do
44
+ assert_raise Dalli::RingError, :message => "No server available" do
45
+ dc = Dalli::Client.new('localhost:19123')
46
+ dc.get('abc')
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,89 @@
1
+ require 'helper'
2
+
3
+ class TestRing < Test::Unit::TestCase
4
+
5
+ context 'a ring of servers' do
6
+
7
+ should "have the continuum sorted by value" do
8
+ servers = [stub(:hostname => "localhost", :port => "11211", :weight => 1),
9
+ stub(:hostname => "localhost", :port => "9500", :weight => 1)]
10
+ ring = Dalli::Ring.new(servers, {})
11
+ previous_value = 0
12
+ ring.continuum.each do |entry|
13
+ assert entry.value > previous_value
14
+ previous_value = entry.value
15
+ end
16
+ end
17
+
18
+ should 'raise when no servers are available/defined' do
19
+ ring = Dalli::Ring.new([], {})
20
+ assert_raise Dalli::RingError, :message => "No server available" do
21
+ ring.server_for_key('test')
22
+ end
23
+ end
24
+
25
+ context 'containing only a single server' do
26
+ should "raise correctly when it's not alive" do
27
+ servers = [
28
+ Dalli::Server.new("localhost:12345"),
29
+ ]
30
+ ring = Dalli::Ring.new(servers, {})
31
+ assert_raise Dalli::RingError, :message => "No server available" do
32
+ ring.server_for_key('test')
33
+ end
34
+ end
35
+
36
+ should "return the server when it's alive" do
37
+ servers = [
38
+ Dalli::Server.new("localhost:19191"),
39
+ ]
40
+ ring = Dalli::Ring.new(servers, {})
41
+ memcached(19191) do |mc|
42
+ ring = mc.send(:ring)
43
+ assert_equal ring.servers.first.port, ring.server_for_key('test').port
44
+ end
45
+ end
46
+ end
47
+
48
+ context 'containing multiple servers' do
49
+ should "raise correctly when no server is alive" do
50
+ servers = [
51
+ Dalli::Server.new("localhost:12345"),
52
+ Dalli::Server.new("localhost:12346"),
53
+ ]
54
+ ring = Dalli::Ring.new(servers, {})
55
+ assert_raise Dalli::RingError, :message => "No server available" do
56
+ ring.server_for_key('test')
57
+ end
58
+ end
59
+
60
+ should "return an alive server when at least one is alive" do
61
+ servers = [
62
+ Dalli::Server.new("localhost:12346"),
63
+ Dalli::Server.new("localhost:19191"),
64
+ ]
65
+ ring = Dalli::Ring.new(servers, {})
66
+ memcached(19191) do |mc|
67
+ ring = mc.send(:ring)
68
+ assert_equal ring.servers.first.port, ring.server_for_key('test').port
69
+ end
70
+ end
71
+ end
72
+
73
+ should 'detect when a dead server is up again' do
74
+ memcached(29125) do
75
+ down_retry_delay = 0.5
76
+ dc = Dalli::Client.new(['localhost:29125', 'localhost:29126'], :down_retry_delay => down_retry_delay)
77
+ assert_equal 1, dc.stats.values.compact.count
78
+
79
+ memcached(29126) do
80
+ assert_equal 1, dc.stats.values.compact.count
81
+
82
+ sleep(down_retry_delay+0.1)
83
+
84
+ assert_equal 2, dc.stats.values.compact.count
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,79 @@
1
+ require 'helper'
2
+
3
+ class TestSasl < Test::Unit::TestCase
4
+
5
+ context 'a server requiring authentication' do
6
+
7
+ context 'without authentication credentials' do
8
+ setup do
9
+ ENV['MEMCACHE_USERNAME'] = 'foo'
10
+ ENV['MEMCACHE_PASSWORD'] = 'wrongpwd'
11
+ end
12
+
13
+ teardown do
14
+ ENV['MEMCACHE_USERNAME'] = nil
15
+ ENV['MEMCACHE_PASSWORD'] = nil
16
+ end
17
+
18
+ should 'gracefully handle authentication failures' do
19
+ memcached(19124, '-S') do |dc|
20
+ assert_raise Dalli::DalliError, /32/ do
21
+ dc.set('abc', 123)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ should 'fail SASL authentication with wrong options' do
28
+ memcached(19124, '-S') do |dc|
29
+ dc = Dalli::Client.new('localhost:19124', :username => 'foo', :password => 'wrongpwd')
30
+ assert_raise Dalli::DalliError, /32/ do
31
+ dc.set('abc', 123)
32
+ end
33
+ end
34
+ end
35
+
36
+ # OSX: Create a SASL user for the memcached application like so:
37
+ #
38
+ # saslpasswd2 -a memcached -c testuser
39
+ #
40
+ # with password 'testtest'
41
+ context 'in an authenticated environment' do
42
+ setup do
43
+ ENV['MEMCACHE_USERNAME'] = 'testuser'
44
+ ENV['MEMCACHE_PASSWORD'] = 'testtest'
45
+ end
46
+
47
+ teardown do
48
+ ENV['MEMCACHE_USERNAME'] = nil
49
+ ENV['MEMCACHE_PASSWORD'] = nil
50
+ end
51
+
52
+ should 'pass SASL authentication' do
53
+ memcached(19124, '-S') do |dc|
54
+ # I get "Dalli::DalliError: Error authenticating: 32" in OSX
55
+ # but SASL works on Heroku servers. YMMV.
56
+ assert_equal true, dc.set('abc', 123)
57
+ assert_equal 123, dc.get('abc')
58
+ results = dc.stats
59
+ assert_equal 1, results.size
60
+ assert_equal 38, results.values.first.size
61
+ end
62
+ end
63
+ end
64
+
65
+ should 'pass SASL authentication with options' do
66
+ memcached(19124, '-S') do |dc|
67
+ dc = Dalli::Client.new('localhost:19124', :username => 'testuser', :password => 'testtest')
68
+ # I get "Dalli::DalliError: Error authenticating: 32" in OSX
69
+ # but SASL works on Heroku servers. YMMV.
70
+ assert_equal true, dc.set('abc', 123)
71
+ assert_equal 123, dc.get('abc')
72
+ results = dc.stats
73
+ assert_equal 1, results.size
74
+ assert_equal 38, results.values.first.size
75
+ end
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,230 @@
1
+ require 'helper'
2
+
3
+ if RAILS_VERSION =~ /3\.0\./
4
+ # Session testing is complex enough that I can't test it in both Rails
5
+ # 3.0 and 2.3. Help is welcome.
6
+
7
+ require 'abstract_unit'
8
+ require 'action_dispatch/middleware/session/dalli_store'
9
+
10
+ class Foo
11
+ def initialize(bar='baz')
12
+ @bar = bar
13
+ end
14
+ def inspect
15
+ "#<#{self.class} bar:#{@bar.inspect}>"
16
+ end
17
+ end
18
+
19
+ class TestSessionStore < ActionController::IntegrationTest
20
+ class TestController < ActionController::Base
21
+ def no_session_access
22
+ head :ok
23
+ end
24
+
25
+ def set_session_value
26
+ session[:foo] = "bar"
27
+ head :ok
28
+ end
29
+
30
+ def set_serialized_session_value
31
+ session[:foo] = Foo.new
32
+ head :ok
33
+ end
34
+
35
+ def get_session_value
36
+ render :text => "foo: #{session[:foo].inspect}"
37
+ end
38
+
39
+ def get_session_id
40
+ render :text => "#{request.session_options[:id]}"
41
+ end
42
+
43
+ def call_reset_session
44
+ session[:bar]
45
+ reset_session
46
+ session[:bar] = "baz"
47
+ head :ok
48
+ end
49
+
50
+ def rescue_action(e) raise end
51
+ end
52
+
53
+ begin
54
+ require 'dalli'
55
+ memcache = Dalli::Client.new('127.0.0.1:11211')
56
+ memcache.set('ping', '')
57
+
58
+ def test_setting_and_getting_session_value
59
+ with_test_route_set do
60
+ get '/set_session_value'
61
+ assert_response :success
62
+ assert cookies['_session_id']
63
+
64
+ get '/get_session_value'
65
+ assert_response :success
66
+ assert_equal 'foo: "bar"', response.body
67
+ end
68
+ end
69
+
70
+ def test_getting_nil_session_value
71
+ with_test_route_set do
72
+ get '/get_session_value'
73
+ assert_response :success
74
+ assert_equal 'foo: nil', response.body
75
+ end
76
+ end
77
+
78
+ def test_getting_session_value_after_session_reset
79
+ with_test_route_set do
80
+ get '/set_session_value'
81
+ assert_response :success
82
+ assert cookies['_session_id']
83
+ session_cookie = cookies.send(:hash_for)['_session_id']
84
+
85
+ get '/call_reset_session'
86
+ assert_response :success
87
+ assert_not_equal [], headers['Set-Cookie']
88
+
89
+ cookies << session_cookie # replace our new session_id with our old, pre-reset session_id
90
+
91
+ get '/get_session_value'
92
+ assert_response :success
93
+ assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
94
+ end
95
+ end
96
+
97
+ def test_getting_from_nonexistent_session
98
+ with_test_route_set do
99
+ get '/get_session_value'
100
+ assert_response :success
101
+ assert_equal 'foo: nil', response.body
102
+ assert_nil cookies['_session_id'], "should only create session on write, not read"
103
+ end
104
+ end
105
+
106
+ def test_setting_session_value_after_session_reset
107
+ with_test_route_set do
108
+ get '/set_session_value'
109
+ assert_response :success
110
+ assert cookies['_session_id']
111
+ session_id = cookies['_session_id']
112
+
113
+ get '/call_reset_session'
114
+ assert_response :success
115
+ assert_not_equal [], headers['Set-Cookie']
116
+
117
+ get '/get_session_value'
118
+ assert_response :success
119
+ assert_equal 'foo: nil', response.body
120
+
121
+ get '/get_session_id'
122
+ assert_response :success
123
+ assert_not_equal session_id, response.body
124
+ end
125
+ end
126
+
127
+ def test_getting_session_id
128
+ with_test_route_set do
129
+ get '/set_session_value'
130
+ assert_response :success
131
+ assert cookies['_session_id']
132
+ session_id = cookies['_session_id']
133
+
134
+ get '/get_session_id'
135
+ assert_response :success
136
+ assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
137
+ end
138
+ end
139
+
140
+ def test_deserializes_unloaded_class
141
+ with_test_route_set do
142
+ with_autoload_path "session_autoload_test" do
143
+ get '/set_serialized_session_value'
144
+ assert_response :success
145
+ assert cookies['_session_id']
146
+ end
147
+ with_autoload_path "session_autoload_test" do
148
+ get '/get_session_id'
149
+ assert_response :success
150
+ end
151
+ with_autoload_path "session_autoload_test" do
152
+ get '/get_session_value'
153
+ assert_response :success
154
+ assert_equal 'foo: #<Foo bar:"baz">', response.body, "should auto-load unloaded class"
155
+ end
156
+ end
157
+ end
158
+
159
+ def test_doesnt_write_session_cookie_if_session_id_is_already_exists
160
+ with_test_route_set do
161
+ get '/set_session_value'
162
+ assert_response :success
163
+ assert cookies['_session_id']
164
+
165
+ get '/get_session_value'
166
+ assert_response :success
167
+ assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
168
+ end
169
+ end
170
+
171
+ def test_prevents_session_fixation
172
+ with_test_route_set do
173
+ get '/get_session_value'
174
+ assert_response :success
175
+ assert_equal 'foo: nil', response.body
176
+ session_id = cookies['_session_id']
177
+
178
+ reset!
179
+
180
+ get '/set_session_value', :_session_id => session_id
181
+ assert_response :success
182
+ assert_not_equal session_id, cookies['_session_id']
183
+ end
184
+ end
185
+
186
+ def test_expire_after
187
+ with_test_route_set(:expire_after => 1) do
188
+ get '/set_session_value'
189
+ assert_match /expires/, @response.headers['Set-Cookie']
190
+
191
+ sleep(1)
192
+
193
+ get '/get_session_value'
194
+ assert_equal 'foo: nil', response.body
195
+ end
196
+ end
197
+
198
+ def test_expires_in
199
+ with_test_route_set(:expires_in => 1) do
200
+ get '/set_session_value'
201
+ assert_no_match /expires/, @response.headers['Set-Cookie']
202
+
203
+ sleep(1)
204
+
205
+ get '/get_session_value'
206
+ assert_equal 'foo: nil', response.body
207
+ end
208
+ end
209
+ rescue LoadError, RuntimeError
210
+ $stderr.puts "Skipping TestSessionStore tests. Start memcached and try again: #{$!.message}"
211
+ end
212
+
213
+ private
214
+ def with_test_route_set(options = {})
215
+ options = {:key => '_session_id', :memcache_server => '127.0.0.1:11211'}.merge(options)
216
+ with_routing do |set|
217
+ set.draw do |map|
218
+ match ':action', :to => ::TestSessionStore::TestController
219
+ end
220
+
221
+ @app = self.class.build_app(set) do |middleware|
222
+ middleware.use ActionDispatch::Session::DalliStore, options
223
+ middleware.delete "ActionDispatch::ShowExceptions"
224
+ end
225
+
226
+ yield
227
+ end
228
+ end
229
+ end
230
+ end