jashmenn-dalli 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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