dalli 2.3.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dalli might be problematic. Click here for more details.
- data/History.md +15 -0
- data/README.md +4 -0
- data/lib/active_support/cache/dalli_store.rb +8 -10
- data/lib/dalli.rb +15 -1
- data/lib/dalli/client.rb +22 -6
- data/lib/dalli/compressor.rb +13 -0
- data/lib/dalli/server.rb +42 -19
- data/lib/dalli/version.rb +1 -1
- data/test/helper.rb +6 -6
- data/test/test_active_support.rb +5 -0
- data/test/test_compressor.rb +36 -0
- data/test/test_dalli.rb +21 -25
- data/test/test_rack_session.rb +7 -0
- data/test/test_serializer.rb +1 -1
- metadata +117 -109
- data/test/abstract_unit.rb +0 -281
- data/test/test_session_store.rb +0 -262
data/History.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
Dalli Changelog
|
2
2
|
=====================
|
3
3
|
|
4
|
+
2.5.0
|
5
|
+
=======
|
6
|
+
|
7
|
+
- Don't escape non-ASCII keys, memcached binary protocol doesn't care. [#257]
|
8
|
+
- :dalli_store now implements LocalCache [#236]
|
9
|
+
- Removed lots of old session_store test code, tests now all run without a default memcached server [#275]
|
10
|
+
- Changed Dalli ActiveSupport adapter to always attempt instrumentation [brianmario, #284]
|
11
|
+
- Change write operations (add/set/replace) to return false when value is too large to store [brianmario, #283]
|
12
|
+
|
13
|
+
2.4.0
|
14
|
+
=======
|
15
|
+
- Added the ability to swap out the compressed used to [de]compress cache data [brianmario, #276]
|
16
|
+
- Fix get\_multi performance issues with lots of memcached servers [tmm1]
|
17
|
+
- Throw more specific exceptions [tmm1]
|
18
|
+
|
4
19
|
2.3.0
|
5
20
|
=======
|
6
21
|
- Added the ability to swap out the serializer used to [de]serialize cache data [brianmario, #274]
|
data/README.md
CHANGED
@@ -108,6 +108,10 @@ Dalli::Client accepts the following options. All times are in seconds.
|
|
108
108
|
|
109
109
|
**compress**: Boolean, if true Dalli will gzip-compress values larger than 1K.
|
110
110
|
|
111
|
+
**compression_min_size**: Minimum value byte size for which to attempt compression. Default is 1K.
|
112
|
+
|
113
|
+
**compression_max_size**: Maximum value byte size for which to attempt compression. Default is unlimited.
|
114
|
+
|
111
115
|
**socket_timeout**: Timeout for all socket operations (connect, read, write). Default is 0.5.
|
112
116
|
|
113
117
|
**socket_max_failures**: When a socket operation fails after socket_timeout, the same operation is retried. This is to not immediately mark a server down when there's a very slight network problem. Default is 2.
|
@@ -45,6 +45,8 @@ module ActiveSupport
|
|
45
45
|
addresses
|
46
46
|
end
|
47
47
|
@data = Dalli::Client.new(servers, @options)
|
48
|
+
|
49
|
+
extend Strategy::LocalCache
|
48
50
|
end
|
49
51
|
|
50
52
|
def fetch(name, options=nil)
|
@@ -106,8 +108,9 @@ module ActiveSupport
|
|
106
108
|
options ||= {}
|
107
109
|
name = expanded_key name
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
+
instrument(:delete, name, options) do |payload|
|
112
|
+
delete_entry(name, options)
|
113
|
+
end
|
111
114
|
end
|
112
115
|
|
113
116
|
# Reads multiple keys from the cache using a single call to the
|
@@ -251,20 +254,15 @@ module ActiveSupport
|
|
251
254
|
def escape(key)
|
252
255
|
key = key.to_s.dup
|
253
256
|
key = key.force_encoding("BINARY") if key.respond_to?(:encode)
|
254
|
-
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
255
257
|
key
|
256
258
|
end
|
257
259
|
|
258
260
|
def instrument(operation, key, options=nil)
|
259
261
|
log(operation, key, options)
|
260
262
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
265
|
-
else
|
266
|
-
yield(nil)
|
267
|
-
end
|
263
|
+
payload = { :key => key }
|
264
|
+
payload.merge!(options) if options.is_a?(Hash)
|
265
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
268
266
|
end
|
269
267
|
|
270
268
|
def log(operation, key, options=nil)
|
data/lib/dalli.rb
CHANGED
@@ -4,6 +4,7 @@ require 'dalli/server'
|
|
4
4
|
require 'dalli/socket'
|
5
5
|
require 'dalli/version'
|
6
6
|
require 'dalli/options'
|
7
|
+
require 'dalli/compressor'
|
7
8
|
require 'dalli/railtie' if defined?(::Rails::Railtie)
|
8
9
|
|
9
10
|
module Dalli
|
@@ -13,8 +14,10 @@ module Dalli
|
|
13
14
|
class NetworkError < DalliError; end
|
14
15
|
# no server available/alive error
|
15
16
|
class RingError < DalliError; end
|
16
|
-
# application error in marshalling
|
17
|
+
# application error in marshalling serialization
|
17
18
|
class MarshalError < DalliError; end
|
19
|
+
# application error in marshalling deserialization or decompression
|
20
|
+
class UnmarshalError < DalliError; end
|
18
21
|
|
19
22
|
def self.logger
|
20
23
|
@logger ||= (rails_logger || default_logger)
|
@@ -46,6 +49,17 @@ module Dalli
|
|
46
49
|
def self.serializer=(serializer)
|
47
50
|
@serializer = serializer
|
48
51
|
end
|
52
|
+
|
53
|
+
# Default serialization to Dalli::Compressor
|
54
|
+
@compressor = Compressor
|
55
|
+
|
56
|
+
def self.compressor
|
57
|
+
@compressor
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.compressor=(compressor)
|
61
|
+
@compressor = compressor
|
62
|
+
end
|
49
63
|
end
|
50
64
|
|
51
65
|
if defined?(RAILS_VERSION) && RAILS_VERSION < '3'
|
data/lib/dalli/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'digest/md5'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
# encoding: ascii
|
4
5
|
module Dalli
|
@@ -20,13 +21,14 @@ module Dalli
|
|
20
21
|
# - :failover - if a server is down, look for and store values on another server in the ring. Default: true.
|
21
22
|
# - :threadsafe - ensure that only one thread is actively using a socket at a time. Default: true.
|
22
23
|
# - :expires_in - default TTL in seconds if you do not pass TTL as a parameter to an individual operation, defaults to 0 or forever
|
23
|
-
# - :compress - defaults to false, if true Dalli will compress values larger than
|
24
|
+
# - :compress - defaults to false, if true Dalli will compress values larger than 1024 bytes before
|
24
25
|
# sending them to memcached.
|
25
26
|
#
|
26
27
|
def initialize(servers=nil, options={})
|
27
28
|
@servers = servers || env_servers || '127.0.0.1:11211'
|
28
29
|
@options = normalize_options(options)
|
29
30
|
@ring = nil
|
31
|
+
@servers_in_use = nil
|
30
32
|
end
|
31
33
|
|
32
34
|
#
|
@@ -58,29 +60,33 @@ module Dalli
|
|
58
60
|
options = nil
|
59
61
|
options = keys.pop if keys.last.is_a?(Hash) || keys.last.nil?
|
60
62
|
ring.lock do
|
63
|
+
self.servers_in_use = Set.new
|
64
|
+
|
61
65
|
keys.flatten.each do |key|
|
62
66
|
begin
|
63
67
|
perform(:getkq, key)
|
64
68
|
rescue DalliError, NetworkError => e
|
65
|
-
Dalli.logger.debug { e.
|
69
|
+
Dalli.logger.debug { e.inspect }
|
66
70
|
Dalli.logger.debug { "unable to get key #{key}" }
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
70
74
|
values = {}
|
71
|
-
|
75
|
+
servers_in_use.each do |server|
|
72
76
|
next unless server.alive?
|
73
77
|
begin
|
74
78
|
server.request(:noop).each_pair do |key, value|
|
75
79
|
values[key_without_namespace(key)] = value
|
76
80
|
end
|
77
81
|
rescue DalliError, NetworkError => e
|
78
|
-
Dalli.logger.debug { e.
|
82
|
+
Dalli.logger.debug { e.inspect }
|
79
83
|
Dalli.logger.debug { "results from this server will be missing" }
|
80
84
|
end
|
81
85
|
end
|
82
86
|
values
|
83
87
|
end
|
88
|
+
ensure
|
89
|
+
self.servers_in_use = nil
|
84
90
|
end
|
85
91
|
|
86
92
|
def fetch(key, ttl=nil, options=nil)
|
@@ -264,14 +270,24 @@ module Dalli
|
|
264
270
|
key = validate_key(key)
|
265
271
|
begin
|
266
272
|
server = ring.server_for_key(key)
|
267
|
-
server.request(op, key, *args)
|
273
|
+
ret = server.request(op, key, *args)
|
274
|
+
servers_in_use << server if servers_in_use
|
275
|
+
ret
|
268
276
|
rescue NetworkError => e
|
269
|
-
Dalli.logger.debug { e.
|
277
|
+
Dalli.logger.debug { e.inspect }
|
270
278
|
Dalli.logger.debug { "retrying request with new server" }
|
271
279
|
retry
|
272
280
|
end
|
273
281
|
end
|
274
282
|
|
283
|
+
def servers_in_use
|
284
|
+
Thread.current[:"#{object_id}-servers"]
|
285
|
+
end
|
286
|
+
|
287
|
+
def servers_in_use=(value)
|
288
|
+
Thread.current[:"#{object_id}-servers"] = value
|
289
|
+
end
|
290
|
+
|
275
291
|
def validate_key(key)
|
276
292
|
raise ArgumentError, "key cannot be blank" if !key || key.length == 0
|
277
293
|
key = key_with_namespace(key)
|
data/lib/dalli/server.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'timeout'
|
3
|
-
require 'zlib'
|
4
3
|
|
5
4
|
module Dalli
|
6
5
|
class Server
|
@@ -20,6 +19,10 @@ module Dalli
|
|
20
19
|
:socket_failure_delay => 0.01,
|
21
20
|
# max size of value in bytes (default is 1 MB, can be overriden with "memcached -I <size>")
|
22
21
|
:value_max_bytes => 1024 * 1024,
|
22
|
+
# min byte size to attempt compression
|
23
|
+
:compression_min_size => 1024,
|
24
|
+
# max byte size for compression
|
25
|
+
:compression_max_size => false,
|
23
26
|
:username => nil,
|
24
27
|
:password => nil,
|
25
28
|
:keepalive => true
|
@@ -164,24 +167,37 @@ module Dalli
|
|
164
167
|
def set(key, value, ttl, cas, options)
|
165
168
|
(value, flags) = serialize(key, value, options)
|
166
169
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
+
if under_max_value_size?(value)
|
171
|
+
req = [REQUEST, OPCODES[multi? ? :setq : :set], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, flags, ttl, key, value].pack(FORMAT[:set])
|
172
|
+
write(req)
|
173
|
+
generic_response unless multi?
|
174
|
+
else
|
175
|
+
false
|
176
|
+
end
|
170
177
|
end
|
171
178
|
|
172
179
|
def add(key, value, ttl, options)
|
173
180
|
(value, flags) = serialize(key, value, options)
|
174
181
|
|
175
|
-
|
176
|
-
|
177
|
-
|
182
|
+
if under_max_value_size?(value)
|
183
|
+
req = [REQUEST, OPCODES[multi? ? :addq : :add], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:add])
|
184
|
+
write(req)
|
185
|
+
generic_response unless multi?
|
186
|
+
else
|
187
|
+
false
|
188
|
+
end
|
178
189
|
end
|
179
190
|
|
180
191
|
def replace(key, value, ttl, options)
|
181
192
|
(value, flags) = serialize(key, value, options)
|
182
|
-
|
183
|
-
|
184
|
-
|
193
|
+
|
194
|
+
if under_max_value_size?(value)
|
195
|
+
req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:replace])
|
196
|
+
write(req)
|
197
|
+
generic_response unless multi?
|
198
|
+
else
|
199
|
+
false
|
200
|
+
end
|
185
201
|
end
|
186
202
|
|
187
203
|
def delete(key)
|
@@ -268,8 +284,6 @@ module Dalli
|
|
268
284
|
generic_response
|
269
285
|
end
|
270
286
|
|
271
|
-
COMPRESSION_MIN_SIZE = 1024
|
272
|
-
|
273
287
|
# http://www.hjp.at/zettel/m/memcached_flags.rxml
|
274
288
|
# Looks like most clients use bit 0 to indicate native language serialization
|
275
289
|
# and bit 1 to indicate gzip compression.
|
@@ -293,11 +307,12 @@ module Dalli
|
|
293
307
|
value.to_s
|
294
308
|
end
|
295
309
|
compressed = false
|
296
|
-
if @options[:compress] && value.bytesize >=
|
297
|
-
value
|
310
|
+
if @options[:compress] && value.bytesize >= @options[:compression_min_size] &&
|
311
|
+
(!@options[:compression_max_size] || value.bytesize <= @options[:compression_max_size])
|
312
|
+
value = Dalli.compressor.compress(value)
|
298
313
|
compressed = true
|
299
314
|
end
|
300
|
-
|
315
|
+
|
301
316
|
flags = 0
|
302
317
|
flags |= FLAG_COMPRESSED if compressed
|
303
318
|
flags |= FLAG_SERIALIZED if marshalled
|
@@ -305,13 +320,17 @@ module Dalli
|
|
305
320
|
end
|
306
321
|
|
307
322
|
def deserialize(value, flags)
|
308
|
-
value =
|
323
|
+
value = Dalli.compressor.decompress(value) if (flags & FLAG_COMPRESSED) != 0
|
309
324
|
value = Dalli.serializer.load(value) if (flags & FLAG_SERIALIZED) != 0
|
310
325
|
value
|
311
|
-
rescue TypeError
|
312
|
-
raise
|
326
|
+
rescue TypeError
|
327
|
+
raise if $!.message !~ /needs to have method `_load'|exception class\/object expected|instance of IO needed|incompatible marshal file format/
|
328
|
+
raise UnmarshalError, "Unable to unmarshal value: #{$!.message}"
|
329
|
+
rescue ArgumentError
|
330
|
+
raise if $!.message !~ /undefined class|marshal data too short/
|
331
|
+
raise UnmarshalError, "Unable to unmarshal value: #{$!.message}"
|
313
332
|
rescue Zlib::Error
|
314
|
-
raise
|
333
|
+
raise UnmarshalError, "Unable to uncompress value: #{$!.message}"
|
315
334
|
end
|
316
335
|
|
317
336
|
def cas_response
|
@@ -335,6 +354,10 @@ module Dalli
|
|
335
354
|
NORMAL_HEADER = '@4CCnN'
|
336
355
|
KV_HEADER = '@2n@6nN'
|
337
356
|
|
357
|
+
def under_max_value_size?(value)
|
358
|
+
value.bytesize <= @options[:value_max_bytes]
|
359
|
+
end
|
360
|
+
|
338
361
|
def generic_response(unpack=false)
|
339
362
|
header = read(24)
|
340
363
|
raise Dalli::NetworkError, 'No response' if !header
|
data/lib/dalli/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -2,17 +2,17 @@ $TESTING = true
|
|
2
2
|
require 'rubygems'
|
3
3
|
# require 'simplecov'
|
4
4
|
# SimpleCov.start
|
5
|
+
require 'minitest/pride'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'mocha/setup'
|
8
|
+
require 'mini_shoulda'
|
9
|
+
require 'memcached_mock'
|
10
|
+
|
5
11
|
WANT_RAILS_VERSION = ENV['RAILS_VERSION'] || '>= 3.0.0'
|
6
12
|
gem 'rails', WANT_RAILS_VERSION
|
7
13
|
require 'rails'
|
8
14
|
puts "Testing with Rails #{Rails.version}"
|
9
15
|
|
10
|
-
require 'mini_shoulda'
|
11
|
-
require 'minitest/pride'
|
12
|
-
require 'minitest/autorun'
|
13
|
-
require 'memcached_mock'
|
14
|
-
require 'mocha'
|
15
|
-
|
16
16
|
require 'dalli'
|
17
17
|
require 'logger'
|
18
18
|
|
data/test/test_active_support.rb
CHANGED
@@ -138,6 +138,11 @@ describe 'ActiveSupport' do
|
|
138
138
|
|
139
139
|
dres = @dalli.delete(user)
|
140
140
|
assert_equal true, dres
|
141
|
+
|
142
|
+
bigkey = '123456789012345678901234567890'
|
143
|
+
@dalli.write(bigkey, 'double width')
|
144
|
+
assert_equal 'double width', @dalli.read(bigkey)
|
145
|
+
assert_equal({bigkey => "double width"}, @dalli.read_multi(bigkey))
|
141
146
|
end
|
142
147
|
end
|
143
148
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'helper'
|
3
|
+
require 'json'
|
4
|
+
require 'memcached_mock'
|
5
|
+
|
6
|
+
class NoopCompressor
|
7
|
+
def self.compress(data)
|
8
|
+
data
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.decompress(data)
|
12
|
+
data
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'Compressor' do
|
17
|
+
|
18
|
+
should 'default to Dalli::Compressor' do
|
19
|
+
assert_equal Dalli::Compressor, Dalli.compressor
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'support a custom compressor' do
|
23
|
+
original_compressor = Dalli.compressor
|
24
|
+
begin
|
25
|
+
Dalli.compressor = NoopCompressor
|
26
|
+
assert_equal NoopCompressor, Dalli.compressor
|
27
|
+
|
28
|
+
memcached(19127) do |dc|
|
29
|
+
assert dc.set("string-test", "a test string")
|
30
|
+
assert_equal("a test string", dc.get("string-test"))
|
31
|
+
end
|
32
|
+
ensure
|
33
|
+
Dalli.compressor = original_compressor
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/test/test_dalli.rb
CHANGED
@@ -27,18 +27,19 @@ describe 'Dalli' do
|
|
27
27
|
|
28
28
|
describe 'key validation' do
|
29
29
|
should 'not allow blanks' do
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
memcached do |dc|
|
31
|
+
dc.set ' ', 1
|
32
|
+
assert_equal 1, dc.get(' ')
|
33
|
+
dc.set "\t", 1
|
34
|
+
assert_equal 1, dc.get("\t")
|
35
|
+
dc.set "\n", 1
|
36
|
+
assert_equal 1, dc.get("\n")
|
37
|
+
assert_raises ArgumentError do
|
38
|
+
dc.set "", 1
|
39
|
+
end
|
40
|
+
assert_raises ArgumentError do
|
41
|
+
dc.set nil, 1
|
42
|
+
end
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -73,11 +74,7 @@ describe 'Dalli' do
|
|
73
74
|
dc.flush
|
74
75
|
|
75
76
|
val1 = "1234567890"*105000
|
76
|
-
|
77
|
-
dc.set('a', val1)
|
78
|
-
val2 = dc.get('a')
|
79
|
-
assert_equal val1, val2
|
80
|
-
end
|
77
|
+
assert_equal false, dc.set('a', val1)
|
81
78
|
|
82
79
|
val1 = "1234567890"*100000
|
83
80
|
dc.set('a', val1)
|
@@ -275,7 +272,7 @@ describe 'Dalli' do
|
|
275
272
|
|
276
273
|
# rollover the 64-bit value, we'll get something undefined.
|
277
274
|
resp = dc.incr('big', 1)
|
278
|
-
0x10000000000000000
|
275
|
+
refute_equal 0x10000000000000000, resp
|
279
276
|
dc.reset
|
280
277
|
end
|
281
278
|
end
|
@@ -327,7 +324,7 @@ describe 'Dalli' do
|
|
327
324
|
should "pass a simple smoke test" do
|
328
325
|
memcached do |dc|
|
329
326
|
resp = dc.flush
|
330
|
-
resp
|
327
|
+
refute_nil resp
|
331
328
|
assert_equal [true, true], resp
|
332
329
|
|
333
330
|
assert_equal true, dc.set(:foo, 'bar')
|
@@ -348,7 +345,7 @@ describe 'Dalli' do
|
|
348
345
|
dc.prepend('123', '0')
|
349
346
|
dc.append('123', '0')
|
350
347
|
|
351
|
-
assert_raises Dalli::
|
348
|
+
assert_raises Dalli::UnmarshalError do
|
352
349
|
resp = dc.get('123')
|
353
350
|
end
|
354
351
|
|
@@ -403,9 +400,10 @@ describe 'Dalli' do
|
|
403
400
|
cache.set('b', 11)
|
404
401
|
inc = cache.incr('cat', 10, 0, 10)
|
405
402
|
cache.set('f', 'zzz')
|
406
|
-
|
403
|
+
res = cache.cas('f') do |value|
|
407
404
|
value << 'z'
|
408
|
-
end
|
405
|
+
end
|
406
|
+
refute_nil res
|
409
407
|
assert_equal false, cache.add('a', 11)
|
410
408
|
assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
|
411
409
|
inc = cache.incr('cat', 10)
|
@@ -469,9 +467,7 @@ describe 'Dalli' do
|
|
469
467
|
dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :compress => true)
|
470
468
|
|
471
469
|
value = "0"*1024*1024
|
472
|
-
|
473
|
-
dc.set('verylarge', value)
|
474
|
-
end
|
470
|
+
assert_equal false, dc.set('verylarge', value)
|
475
471
|
dalli.set('verylarge', value)
|
476
472
|
end
|
477
473
|
end
|
data/test/test_rack_session.rb
CHANGED
@@ -6,6 +6,13 @@ require 'rack/mock'
|
|
6
6
|
require 'thread'
|
7
7
|
|
8
8
|
describe Rack::Session::Dalli do
|
9
|
+
Rack::Session::Dalli::DEFAULT_OPTIONS[:memcache_server] = 'localhost:19129'
|
10
|
+
|
11
|
+
before do
|
12
|
+
memcached(19129) do
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
9
16
|
session_key = Rack::Session::Dalli::DEFAULT_OPTIONS[:key]
|
10
17
|
session_match = /#{session_key}=([0-9a-fA-F]+);/
|
11
18
|
incrementor = lambda do |env|
|
data/test/test_serializer.rb
CHANGED
metadata
CHANGED
@@ -1,130 +1,138 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: dalli
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.5.0
|
4
5
|
prerelease:
|
5
|
-
version: 2.3.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
|
7
|
+
authors:
|
8
|
+
- Mike Perham
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
12
|
+
date: 2012-11-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mini_shoulda
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mocha
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rails
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3'
|
48
62
|
description: High performance memcached client for Ruby
|
49
63
|
email: mperham@gmail.com
|
50
64
|
executables: []
|
51
|
-
|
52
65
|
extensions: []
|
53
|
-
|
54
66
|
extra_rdoc_files: []
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
- test/test_session_store.rb
|
67
|
+
files:
|
68
|
+
- lib/action_dispatch/middleware/session/dalli_store.rb
|
69
|
+
- lib/active_support/cache/dalli_store.rb
|
70
|
+
- lib/dalli/client.rb
|
71
|
+
- lib/dalli/compressor.rb
|
72
|
+
- lib/dalli/options.rb
|
73
|
+
- lib/dalli/railtie.rb
|
74
|
+
- lib/dalli/ring.rb
|
75
|
+
- lib/dalli/server.rb
|
76
|
+
- lib/dalli/socket.rb
|
77
|
+
- lib/dalli/version.rb
|
78
|
+
- lib/dalli.rb
|
79
|
+
- lib/rack/session/dalli.rb
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- History.md
|
83
|
+
- Rakefile
|
84
|
+
- Gemfile
|
85
|
+
- dalli.gemspec
|
86
|
+
- Performance.md
|
87
|
+
- test/benchmark_test.rb
|
88
|
+
- test/helper.rb
|
89
|
+
- test/memcached_mock.rb
|
90
|
+
- test/test_active_support.rb
|
91
|
+
- test/test_compressor.rb
|
92
|
+
- test/test_dalli.rb
|
93
|
+
- test/test_encoding.rb
|
94
|
+
- test/test_failover.rb
|
95
|
+
- test/test_network.rb
|
96
|
+
- test/test_rack_session.rb
|
97
|
+
- test/test_ring.rb
|
98
|
+
- test/test_sasl.rb
|
99
|
+
- test/test_serializer.rb
|
89
100
|
homepage: http://github.com/mperham/dalli
|
90
101
|
licenses: []
|
91
|
-
|
92
102
|
post_install_message:
|
93
|
-
rdoc_options:
|
94
|
-
|
95
|
-
require_paths:
|
96
|
-
|
97
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
rdoc_options:
|
104
|
+
- --charset=UTF-8
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
108
|
none: false
|
99
|
-
requirements:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
114
|
none: false
|
105
|
-
requirements:
|
106
|
-
|
107
|
-
|
108
|
-
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
109
119
|
requirements: []
|
110
|
-
|
111
120
|
rubyforge_project:
|
112
|
-
rubygems_version: 1.8.
|
121
|
+
rubygems_version: 1.8.24
|
113
122
|
signing_key:
|
114
123
|
specification_version: 3
|
115
124
|
summary: High performance memcached client for Ruby
|
116
|
-
test_files:
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
- test/test_session_store.rb
|
125
|
+
test_files:
|
126
|
+
- test/benchmark_test.rb
|
127
|
+
- test/helper.rb
|
128
|
+
- test/memcached_mock.rb
|
129
|
+
- test/test_active_support.rb
|
130
|
+
- test/test_compressor.rb
|
131
|
+
- test/test_dalli.rb
|
132
|
+
- test/test_encoding.rb
|
133
|
+
- test/test_failover.rb
|
134
|
+
- test/test_network.rb
|
135
|
+
- test/test_rack_session.rb
|
136
|
+
- test/test_ring.rb
|
137
|
+
- test/test_sasl.rb
|
138
|
+
- test/test_serializer.rb
|
data/test/abstract_unit.rb
DELETED
@@ -1,281 +0,0 @@
|
|
1
|
-
# Used to test the full Rails stack.
|
2
|
-
# Stolen from the Rails 3.0 source.
|
3
|
-
# Needed for the session store tests.
|
4
|
-
require 'active_support/core_ext/kernel/reporting'
|
5
|
-
require 'active_support/core_ext/string/encoding'
|
6
|
-
if "ruby".encoding_aware?
|
7
|
-
# These are the normal settings that will be set up by Railties
|
8
|
-
# TODO: Have these tests support other combinations of these values
|
9
|
-
silence_warnings do
|
10
|
-
Encoding.default_internal = "UTF-8"
|
11
|
-
Encoding.default_external = "UTF-8"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'test/unit'
|
16
|
-
require 'abstract_controller'
|
17
|
-
require 'action_controller'
|
18
|
-
require 'action_view'
|
19
|
-
require 'action_dispatch'
|
20
|
-
require 'active_support/dependencies'
|
21
|
-
require 'action_controller/caching'
|
22
|
-
require 'action_controller/caching/sweeping'
|
23
|
-
|
24
|
-
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
|
25
|
-
|
26
|
-
module Rails
|
27
|
-
def self.logger
|
28
|
-
@logger ||= begin
|
29
|
-
l = Logger.new(STDOUT)
|
30
|
-
l.level = Logger::INFO; l
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Monkey patch the old routes initialization to be silenced.
|
36
|
-
class ActionDispatch::Routing::DeprecatedMapper
|
37
|
-
def initialize_with_silencer(*args)
|
38
|
-
ActiveSupport::Deprecation.silence { initialize_without_silencer(*args) }
|
39
|
-
end
|
40
|
-
alias_method_chain :initialize, :silencer
|
41
|
-
end
|
42
|
-
|
43
|
-
ActiveSupport::Dependencies.hook!
|
44
|
-
|
45
|
-
# Show backtraces for deprecated behavior for quicker cleanup.
|
46
|
-
ActiveSupport::Deprecation.debug = true
|
47
|
-
|
48
|
-
ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort
|
49
|
-
|
50
|
-
module RackTestUtils
|
51
|
-
def body_to_string(body)
|
52
|
-
if body.respond_to?(:each)
|
53
|
-
str = ""
|
54
|
-
body.each {|s| str << s }
|
55
|
-
str
|
56
|
-
else
|
57
|
-
body
|
58
|
-
end
|
59
|
-
end
|
60
|
-
extend self
|
61
|
-
end
|
62
|
-
|
63
|
-
module SetupOnce
|
64
|
-
extend ActiveSupport::Concern
|
65
|
-
|
66
|
-
included do
|
67
|
-
cattr_accessor :setup_once_block
|
68
|
-
self.setup_once_block = nil
|
69
|
-
|
70
|
-
setup :run_setup_once
|
71
|
-
end
|
72
|
-
|
73
|
-
module ClassMethods
|
74
|
-
def setup_once(&block)
|
75
|
-
self.setup_once_block = block
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
def run_setup_once
|
81
|
-
if self.setup_once_block
|
82
|
-
self.setup_once_block.call
|
83
|
-
self.setup_once_block = nil
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
|
89
|
-
|
90
|
-
module ActiveSupport
|
91
|
-
class TestCase
|
92
|
-
include SetupOnce
|
93
|
-
# Hold off drawing routes until all the possible controller classes
|
94
|
-
# have been loaded.
|
95
|
-
setup_once do
|
96
|
-
SharedTestRoutes.draw do
|
97
|
-
match ':controller(/:action(/:id))'
|
98
|
-
end
|
99
|
-
|
100
|
-
ActionController::IntegrationTest.app.routes.draw do
|
101
|
-
match ':controller(/:action(/:id))'
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
class RoutedRackApp
|
108
|
-
attr_reader :routes
|
109
|
-
|
110
|
-
def initialize(routes, &blk)
|
111
|
-
@routes = routes
|
112
|
-
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
|
113
|
-
end
|
114
|
-
|
115
|
-
def call(env)
|
116
|
-
@stack.call(env)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
class BasicController
|
121
|
-
attr_accessor :request
|
122
|
-
|
123
|
-
def config
|
124
|
-
@config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config|
|
125
|
-
# VIEW TODO: View tests should not require a controller
|
126
|
-
public_dir = File.expand_path("../fixtures/public", __FILE__)
|
127
|
-
config.assets_dir = public_dir
|
128
|
-
config.javascripts_dir = "#{public_dir}/javascripts"
|
129
|
-
config.stylesheets_dir = "#{public_dir}/stylesheets"
|
130
|
-
config
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
|
136
|
-
setup do
|
137
|
-
@routes = SharedTestRoutes
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
142
|
-
def self.build_app(routes = nil)
|
143
|
-
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
|
144
|
-
middleware.use "ActionDispatch::Callbacks"
|
145
|
-
middleware.use "ActionDispatch::ParamsParser"
|
146
|
-
middleware.use "ActionDispatch::Cookies"
|
147
|
-
middleware.use "ActionDispatch::Flash"
|
148
|
-
middleware.use "ActionDispatch::Head"
|
149
|
-
yield(middleware) if block_given?
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
self.app = build_app
|
154
|
-
|
155
|
-
# Stub Rails dispatcher so it does not get controller references and
|
156
|
-
# simply return the controller#action as Rack::Body.
|
157
|
-
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
|
158
|
-
protected
|
159
|
-
def controller_reference(controller_param)
|
160
|
-
controller_param
|
161
|
-
end
|
162
|
-
|
163
|
-
def dispatch(controller, action, env)
|
164
|
-
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.stub_controllers
|
169
|
-
old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
|
170
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
171
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
|
172
|
-
yield ActionDispatch::Routing::RouteSet.new
|
173
|
-
ensure
|
174
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
175
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
|
176
|
-
end
|
177
|
-
|
178
|
-
def with_routing(&block)
|
179
|
-
temporary_routes = ActionDispatch::Routing::RouteSet.new
|
180
|
-
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
|
181
|
-
old_routes = SharedTestRoutes
|
182
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
|
183
|
-
|
184
|
-
yield temporary_routes
|
185
|
-
ensure
|
186
|
-
self.class.app = old_app
|
187
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
|
188
|
-
end
|
189
|
-
|
190
|
-
def with_autoload_path(path)
|
191
|
-
path = File.join(File.dirname(__FILE__), "fixtures", path)
|
192
|
-
if ActiveSupport::Dependencies.autoload_paths.include?(path)
|
193
|
-
yield
|
194
|
-
else
|
195
|
-
begin
|
196
|
-
ActiveSupport::Dependencies.autoload_paths << path
|
197
|
-
yield
|
198
|
-
ensure
|
199
|
-
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
|
200
|
-
ActiveSupport::Dependencies.clear
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# Temporary base class
|
207
|
-
class Rack::TestCase < ActionController::IntegrationTest
|
208
|
-
def self.testing(klass = nil)
|
209
|
-
if klass
|
210
|
-
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
|
211
|
-
else
|
212
|
-
@testing
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def get(thing, *args)
|
217
|
-
if thing.is_a?(Symbol)
|
218
|
-
super("#{self.class.testing}/#{thing}", *args)
|
219
|
-
else
|
220
|
-
super
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def assert_body(body)
|
225
|
-
assert_equal body, Array.wrap(response.body).join
|
226
|
-
end
|
227
|
-
|
228
|
-
def assert_status(code)
|
229
|
-
assert_equal code, response.status
|
230
|
-
end
|
231
|
-
|
232
|
-
def assert_response(body, status = 200, headers = {})
|
233
|
-
assert_body body
|
234
|
-
assert_status status
|
235
|
-
headers.each do |header, value|
|
236
|
-
assert_header header, value
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def assert_content_type(type)
|
241
|
-
assert_equal type, response.headers["Content-Type"]
|
242
|
-
end
|
243
|
-
|
244
|
-
def assert_header(name, value)
|
245
|
-
assert_equal value, response.headers[name]
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
class ActionController::Base
|
250
|
-
def self.test_routes(&block)
|
251
|
-
routes = ActionDispatch::Routing::RouteSet.new
|
252
|
-
routes.draw(&block)
|
253
|
-
include routes.url_helpers
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
class ::ApplicationController < ActionController::Base
|
258
|
-
end
|
259
|
-
|
260
|
-
module ActionController
|
261
|
-
class Base
|
262
|
-
include ActionController::Testing
|
263
|
-
end
|
264
|
-
|
265
|
-
Base.view_paths = []
|
266
|
-
|
267
|
-
class TestCase
|
268
|
-
include ActionDispatch::TestProcess
|
269
|
-
|
270
|
-
setup do
|
271
|
-
@routes = SharedTestRoutes
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
# This stub emulates the Railtie including the URL helpers from a Rails application
|
277
|
-
module ActionController
|
278
|
-
class Base
|
279
|
-
include SharedTestRoutes.url_helpers
|
280
|
-
end
|
281
|
-
end
|
data/test/test_session_store.rb
DELETED
@@ -1,262 +0,0 @@
|
|
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
|
-
include MemcachedMock::Helper
|
16
|
-
|
17
|
-
class TestController < ActionController::Base
|
18
|
-
def no_session_access
|
19
|
-
head :ok
|
20
|
-
end
|
21
|
-
|
22
|
-
def set_session_value
|
23
|
-
session[:foo] = "bar"
|
24
|
-
head :ok
|
25
|
-
end
|
26
|
-
|
27
|
-
def set_serialized_session_value
|
28
|
-
session[:foo] = Foo.new
|
29
|
-
head :ok
|
30
|
-
end
|
31
|
-
|
32
|
-
def get_session_value
|
33
|
-
render :text => "foo: #{session[:foo].inspect}"
|
34
|
-
end
|
35
|
-
|
36
|
-
def get_session_id
|
37
|
-
render :text => "#{request.session_options[:id]}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def call_reset_session
|
41
|
-
session[:bar]
|
42
|
-
reset_session
|
43
|
-
session[:bar] = "baz"
|
44
|
-
head :ok
|
45
|
-
end
|
46
|
-
|
47
|
-
def rescue_action(e) raise end
|
48
|
-
end
|
49
|
-
|
50
|
-
begin
|
51
|
-
require 'dalli'
|
52
|
-
memcache = Dalli::Client.new('127.0.0.1:11211')
|
53
|
-
memcache.set('ping', '')
|
54
|
-
|
55
|
-
def test_setting_and_getting_session_value
|
56
|
-
with_test_route_set do
|
57
|
-
get '/set_session_value'
|
58
|
-
assert_response :success
|
59
|
-
assert cookies['_session_id']
|
60
|
-
|
61
|
-
get '/get_session_value'
|
62
|
-
assert_response :success
|
63
|
-
assert_equal 'foo: "bar"', response.body
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_getting_nil_session_value
|
68
|
-
with_test_route_set do
|
69
|
-
get '/get_session_value'
|
70
|
-
assert_response :success
|
71
|
-
assert_equal 'foo: nil', response.body
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_getting_session_value_after_session_reset
|
76
|
-
with_test_route_set do
|
77
|
-
get '/set_session_value'
|
78
|
-
assert_response :success
|
79
|
-
assert cookies['_session_id']
|
80
|
-
session_cookie = cookies.send(:hash_for)['_session_id']
|
81
|
-
|
82
|
-
get '/call_reset_session'
|
83
|
-
assert_response :success
|
84
|
-
assert_not_equal [], headers['Set-Cookie']
|
85
|
-
|
86
|
-
cookies << session_cookie # replace our new session_id with our old, pre-reset session_id
|
87
|
-
|
88
|
-
get '/get_session_value'
|
89
|
-
assert_response :success
|
90
|
-
assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_getting_from_nonexistent_session
|
95
|
-
with_test_route_set do
|
96
|
-
get '/get_session_value'
|
97
|
-
assert_response :success
|
98
|
-
assert_equal 'foo: nil', response.body
|
99
|
-
assert_nil cookies['_session_id'], "should only create session on write, not read"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_setting_session_value_after_session_reset
|
104
|
-
with_test_route_set do
|
105
|
-
get '/set_session_value'
|
106
|
-
assert_response :success
|
107
|
-
assert cookies['_session_id']
|
108
|
-
session_id = cookies['_session_id']
|
109
|
-
|
110
|
-
get '/call_reset_session'
|
111
|
-
assert_response :success
|
112
|
-
assert_not_equal [], headers['Set-Cookie']
|
113
|
-
|
114
|
-
get '/get_session_value'
|
115
|
-
assert_response :success
|
116
|
-
assert_equal 'foo: nil', response.body
|
117
|
-
|
118
|
-
get '/get_session_id'
|
119
|
-
assert_response :success
|
120
|
-
assert_not_equal session_id, response.body
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def test_getting_session_id
|
125
|
-
with_test_route_set do
|
126
|
-
get '/set_session_value'
|
127
|
-
assert_response :success
|
128
|
-
assert cookies['_session_id']
|
129
|
-
session_id = cookies['_session_id']
|
130
|
-
|
131
|
-
get '/get_session_id'
|
132
|
-
assert_response :success
|
133
|
-
assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def test_deserializes_unloaded_class
|
138
|
-
with_test_route_set do
|
139
|
-
with_autoload_path "session_autoload_test" do
|
140
|
-
get '/set_serialized_session_value'
|
141
|
-
assert_response :success
|
142
|
-
assert cookies['_session_id']
|
143
|
-
end
|
144
|
-
with_autoload_path "session_autoload_test" do
|
145
|
-
get '/get_session_id'
|
146
|
-
assert_response :success
|
147
|
-
end
|
148
|
-
with_autoload_path "session_autoload_test" do
|
149
|
-
get '/get_session_value'
|
150
|
-
assert_response :success
|
151
|
-
assert_equal 'foo: #<Foo bar:"baz">', response.body, "should auto-load unloaded class"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def test_doesnt_write_session_cookie_if_session_id_is_already_exists
|
157
|
-
with_test_route_set do
|
158
|
-
get '/set_session_value'
|
159
|
-
assert_response :success
|
160
|
-
assert cookies['_session_id']
|
161
|
-
|
162
|
-
get '/get_session_value'
|
163
|
-
assert_response :success
|
164
|
-
assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def test_prevents_session_fixation
|
169
|
-
with_test_route_set do
|
170
|
-
get '/get_session_value'
|
171
|
-
assert_response :success
|
172
|
-
assert_equal 'foo: nil', response.body
|
173
|
-
session_id = cookies['_session_id']
|
174
|
-
|
175
|
-
reset!
|
176
|
-
|
177
|
-
get '/set_session_value', :_session_id => session_id
|
178
|
-
assert_response :success
|
179
|
-
assert_not_equal session_id, cookies['_session_id']
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def test_expire_after
|
184
|
-
with_test_route_set(:expire_after => 1) do
|
185
|
-
get '/set_session_value'
|
186
|
-
assert_match(/expires/, @response.headers['Set-Cookie'])
|
187
|
-
|
188
|
-
sleep(1)
|
189
|
-
|
190
|
-
get '/get_session_value'
|
191
|
-
assert_equal 'foo: nil', response.body
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def test_expires_in
|
196
|
-
with_test_route_set(:expires_in => 1) do
|
197
|
-
get '/set_session_value'
|
198
|
-
assert_no_match(/expires/, @response.headers['Set-Cookie'])
|
199
|
-
|
200
|
-
sleep(1)
|
201
|
-
|
202
|
-
get '/get_session_value'
|
203
|
-
assert_equal 'foo: nil', response.body
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def test_without_raise_errors_option
|
208
|
-
memcached(29125) do
|
209
|
-
with_test_route_set(:memcache_server => '127.0.0.1:29125') do
|
210
|
-
get '/set_session_value'
|
211
|
-
assert_response :success
|
212
|
-
|
213
|
-
get '/get_session_value'
|
214
|
-
assert_response :success
|
215
|
-
assert_equal 'foo: "bar"', response.body
|
216
|
-
|
217
|
-
memcached_kill(29125)
|
218
|
-
|
219
|
-
get '/get_session_value'
|
220
|
-
assert_response :success
|
221
|
-
assert_equal 'foo: nil', response.body
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def test_with_raise_errors_option
|
227
|
-
memcached(29125) do
|
228
|
-
with_test_route_set(:memcache_server => '127.0.0.1:29125', :raise_errors => true) do
|
229
|
-
get '/set_session_value'
|
230
|
-
assert_response :success
|
231
|
-
|
232
|
-
memcached_kill(29125)
|
233
|
-
|
234
|
-
exception = [Dalli::RingError, { :message => "No server available" }]
|
235
|
-
|
236
|
-
assert_raises(*exception) { get '/get_session_value' }
|
237
|
-
assert_raises(*exception) { get '/set_session_value' }
|
238
|
-
assert_raises(*exception) { get '/call_reset_session' }
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
|
-
rescue LoadError, RuntimeError
|
243
|
-
$stderr.puts "Skipping SessionStore tests. Start memcached and try again: #{$!.message}"
|
244
|
-
end
|
245
|
-
|
246
|
-
private
|
247
|
-
|
248
|
-
def with_test_route_set(options = {})
|
249
|
-
options = {:key => '_session_id', :memcache_server => '127.0.0.1:11211'}.merge(options)
|
250
|
-
with_routing do |set|
|
251
|
-
set.draw do
|
252
|
-
match ':action', :to => ::TestSessionStore::TestController
|
253
|
-
end
|
254
|
-
|
255
|
-
@app = self.class.build_app(set) do |middleware|
|
256
|
-
middleware.use ActionDispatch::Session::DalliStore, options
|
257
|
-
end
|
258
|
-
|
259
|
-
yield
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|