mob-dalli 1.1.4

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