dalli 2.7.0 → 2.7.1

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4e1d2bd1cdadde91a31a3e1311e4189e54b57623
4
- data.tar.gz: 6e2fbab2dd27e1cf5f62eef39d7292d1ac6f93b8
3
+ metadata.gz: b95a4fab254be40a050b417698b0551ffeb5e81d
4
+ data.tar.gz: c15ffb9b9e417e8188855394a5af9384cc090cc1
5
5
  SHA512:
6
- metadata.gz: ad6caea0b89835f15f7ddc4fd4ecab66eaa87ed969020c41fae9324da520b3e9f3b15afe53d1b14e515eafcb29cbc76c62267ce12a8c708f525ab2863e62f682
7
- data.tar.gz: 8646c41bab51faa972bd16c5e06157c1c201a862f911f3f961b252ce9fd96c1b583345068090b2606f1a302f5d106df072eb7a91acb2ecb1c73464b3ca2f6f58
6
+ metadata.gz: 3d837cb9c4869b6035a271585e4fbd1a41cd91d6d4f19ff910b99e4364d8c401ebb8a8f366c077e4ef70a2809d3d0f49122a9cae8d90ce81490d58e2b13381dd
7
+ data.tar.gz: b8f5499ad63ff4e357557d2a68b32a07251da67244c35c3281b3a90afab928bacdef17842ff4cf4cde938920f4f7210f46eb6e8e0795d8eb3381b15ebe92afd5
data/History.md CHANGED
@@ -1,9 +1,19 @@
1
1
  Dalli Changelog
2
2
  =====================
3
3
 
4
+ 2.7.1
5
+ ==========
6
+
7
+ - Rack session will check if servers are up on initialization (arthurnn, #423)
8
+ - Add support for IPv6 addresses in hex form, ie: "[::1]:11211" (dplummer, #428)
9
+ - Add symbol support for namespace (jingkai #431)
10
+ - Support expiration intervals longer than 30 days (leonid-shevtsov #436)
11
+
4
12
  2.7.0
5
13
  ==========
6
14
 
15
+ - BREAKING CHANGE:
16
+ Dalli::Client#add and #replace now return a truthy value, not boolean true or false.
7
17
  - Multithreading support with dalli\_store:
8
18
  Use :pool\_size to create a pool of shared, threadsafe Dalli clients in Rails:
9
19
  ```ruby
data/README.md CHANGED
@@ -94,6 +94,12 @@ config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
94
94
  { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
95
95
  ```
96
96
 
97
+ If your servers are specified in `ENV["MEMCACHE_SERVERS"]` (e.g. on Heroku when using a third-party hosted addon), simply provide `nil` for the servers:
98
+
99
+ ```ruby
100
+ config.cache_store = :dalli_store, nil, { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
101
+ ```
102
+
97
103
  To use Dalli for Rails session storage that times out after 20 minutes, in `config/initializers/session_store.rb`:
98
104
 
99
105
  For Rails >= 3.2.4:
@@ -124,6 +130,19 @@ add :pool\_size to your `dalli_store` config:
124
130
  config.cache_store = :dalli_store, 'cache-1.example.com', { :pool_size => 5 }
125
131
  ```
126
132
 
133
+ You can then use the Rails cache as normal or check out a Dalli client directly from the pool:
134
+
135
+ ```ruby
136
+ Rails.cache.fetch('foo', :expires_in => 300) do
137
+ 'bar'
138
+ end
139
+
140
+ Rails.cache.dalli.with do |client|
141
+ # client is a Dalli::Client instance which you can
142
+ # use ONLY within this block
143
+ end
144
+ ```
145
+
127
146
 
128
147
  Configuration
129
148
  ------------------------
@@ -24,6 +24,6 @@ Gem::Specification.new do |s|
24
24
  s.test_files = Dir.glob("test/**/*")
25
25
  s.add_development_dependency(%q<minitest>, [">= 4.2.0"])
26
26
  s.add_development_dependency(%q<mocha>, [">= 0"])
27
- s.add_development_dependency(%q<rails>, ["~> 3"])
27
+ s.add_development_dependency(%q<rails>, ["~> 4"])
28
28
  end
29
29
 
@@ -32,7 +32,7 @@ module ActionDispatch
32
32
  private
33
33
 
34
34
  def get_session(env, sid)
35
- sid ||= generate_sid
35
+ sid = generate_sid unless sid and !sid.empty?
36
36
  begin
37
37
  session = @pool.get(sid) || {}
38
38
  rescue Dalli::DalliError => ex
@@ -54,6 +54,8 @@ module ActiveSupport
54
54
  pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
55
55
 
56
56
  @options[:compress] ||= @options[:compression]
57
+
58
+ addresses.compact!
57
59
  servers = if addresses.empty?
58
60
  nil # use the default from Dalli::Client
59
61
  else
@@ -33,7 +33,7 @@ module Dalli
33
33
 
34
34
  ##
35
35
  # Set the key-value pair, verifying existing CAS.
36
- # Returns the resulting CAS value if succeeded, and false otherwise.
36
+ # Returns the resulting CAS value if succeeded, and falsy otherwise.
37
37
  def set_cas(key, value, cas, ttl=nil, options=nil)
38
38
  ttl ||= @options[:expires_in].to_i
39
39
  perform(:set, key, value, ttl, cas, options)
@@ -42,17 +42,17 @@ module Dalli
42
42
  ##
43
43
  # Conditionally add a key/value pair, verifying existing CAS, only if the
44
44
  # key already exists on the server. Returns the new CAS value if the
45
- # operation succeeded, or false otherwise.
45
+ # operation succeeded, or falsy otherwise.
46
46
  def replace_cas(key, value, cas, ttl=nil, options=nil)
47
47
  ttl ||= @options[:expires_in].to_i
48
48
  perform(:replace, key, value, ttl, cas, options)
49
49
  end
50
50
 
51
51
  # Delete a key/value pair, verifying existing CAS.
52
- # Returns true if succeeded, and false otherwise.
52
+ # Returns true if succeeded, and falsy otherwise.
53
53
  def delete_cas(key, cas=0)
54
54
  perform(:delete, key, cas)
55
55
  end
56
56
 
57
57
  end
58
- end
58
+ end
@@ -105,7 +105,7 @@ module Dalli
105
105
 
106
106
  ##
107
107
  # Conditionally add a key/value pair, if the key does not already exist
108
- # on the server. Returns true if the operation succeeded.
108
+ # on the server. Returns truthy if the operation succeeded.
109
109
  def add(key, value, ttl=nil, options=nil)
110
110
  ttl ||= @options[:expires_in].to_i
111
111
  perform(:add, key, value, ttl, options)
@@ -113,7 +113,7 @@ module Dalli
113
113
 
114
114
  ##
115
115
  # Conditionally add a key/value pair, only if the key already exists
116
- # on the server. Returns true if the operation succeeded.
116
+ # on the server. Returns truthy if the operation succeeded.
117
117
  def replace(key, value, ttl=nil, options=nil)
118
118
  ttl ||= @options[:expires_in].to_i
119
119
  perform(:replace, key, value, ttl, 0, options)
@@ -212,6 +212,12 @@ module Dalli
212
212
  end
213
213
  end
214
214
 
215
+ ##
216
+ ## Make sure memcache servers are alive, or raise an Dalli::RingError
217
+ def alive!
218
+ ring.server_for_key("")
219
+ end
220
+
215
221
  ##
216
222
  ## Version of the memcache servers.
217
223
  def version
@@ -348,7 +354,8 @@ module Dalli
348
354
  end
349
355
 
350
356
  def namespace
351
- @options[:namespace].is_a?(Proc) ? @options[:namespace].call : @options[:namespace]
357
+ return nil unless @options[:namespace]
358
+ @options[:namespace].is_a?(Proc) ? @options[:namespace].call.to_s : @options[:namespace].to_s
352
359
  end
353
360
 
354
361
  def normalize_options(opts)
@@ -32,7 +32,7 @@ module Dalli
32
32
  }
33
33
 
34
34
  def initialize(attribs, options = {})
35
- (@hostname, @port, @weight) = attribs.split(':')
35
+ (@hostname, @port, @weight) = parse_hostname(attribs)
36
36
  @port ||= 11211
37
37
  @port = Integer(@port)
38
38
  @weight ||= 1
@@ -268,6 +268,7 @@ module Dalli
268
268
 
269
269
  def set(key, value, ttl, cas, options)
270
270
  (value, flags) = serialize(key, value, options)
271
+ ttl = sanitize_ttl(ttl)
271
272
 
272
273
  guard_max_value(key, value) do
273
274
  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])
@@ -278,6 +279,7 @@ module Dalli
278
279
 
279
280
  def add(key, value, ttl, options)
280
281
  (value, flags) = serialize(key, value, options)
282
+ ttl = sanitize_ttl(ttl)
281
283
 
282
284
  guard_max_value(key, value) do
283
285
  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])
@@ -288,6 +290,7 @@ module Dalli
288
290
 
289
291
  def replace(key, value, ttl, cas, options)
290
292
  (value, flags) = serialize(key, value, options)
293
+ ttl = sanitize_ttl(ttl)
291
294
 
292
295
  guard_max_value(key, value) do
293
296
  req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, flags, ttl, key, value].pack(FORMAT[:replace])
@@ -308,26 +311,32 @@ module Dalli
308
311
  generic_response
309
312
  end
310
313
 
311
- def decr(key, count, ttl, default)
312
- expiry = default ? ttl : 0xFFFFFFFF
314
+ def decr_incr(opcode, key, count, ttl, default)
315
+ expiry = default ? sanitize_ttl(ttl) : 0xFFFFFFFF
313
316
  default ||= 0
314
317
  (h, l) = split(count)
315
318
  (dh, dl) = split(default)
316
- req = [REQUEST, OPCODES[:decr], key.bytesize, 20, 0, 0, key.bytesize + 20, 0, 0, h, l, dh, dl, expiry, key].pack(FORMAT[:decr])
319
+ req = [REQUEST, OPCODES[opcode], key.bytesize, 20, 0, 0, key.bytesize + 20, 0, 0, h, l, dh, dl, expiry, key].pack(FORMAT[opcode])
317
320
  write(req)
318
321
  body = generic_response
319
- body ? longlong(*body.unpack('NN')) : body
322
+ body ? body.unpack('Q>').first : body
323
+ end
324
+
325
+ def decr(key, count, ttl, default)
326
+ decr_incr :decr, key, count, ttl, default
320
327
  end
321
328
 
322
329
  def incr(key, count, ttl, default)
323
- expiry = default ? ttl : 0xFFFFFFFF
324
- default ||= 0
325
- (h, l) = split(count)
326
- (dh, dl) = split(default)
327
- req = [REQUEST, OPCODES[:incr], key.bytesize, 20, 0, 0, key.bytesize + 20, 0, 0, h, l, dh, dl, expiry, key].pack(FORMAT[:incr])
328
- write(req)
329
- body = generic_response
330
- body ? longlong(*body.unpack('NN')) : body
330
+ decr_incr :incr, key, count, ttl, default
331
+ end
332
+
333
+ def write_append_prepend(opcode, key, value)
334
+ write_generic [REQUEST, OPCODES[opcode], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[opcode])
335
+ end
336
+
337
+ def write_generic(bytes)
338
+ write(bytes)
339
+ generic_response
331
340
  end
332
341
 
333
342
  def write_noop
@@ -343,15 +352,11 @@ module Dalli
343
352
  end
344
353
 
345
354
  def append(key, value)
346
- req = [REQUEST, OPCODES[:append], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[:append])
347
- write(req)
348
- generic_response
355
+ write_append_prepend :append, key, value
349
356
  end
350
357
 
351
358
  def prepend(key, value)
352
- req = [REQUEST, OPCODES[:prepend], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[:prepend])
353
- write(req)
354
- generic_response
359
+ write_append_prepend :prepend, key, value
355
360
  end
356
361
 
357
362
  def stats(info='')
@@ -361,9 +366,7 @@ module Dalli
361
366
  end
362
367
 
363
368
  def reset_stats
364
- req = [REQUEST, OPCODES[:stat], 'reset'.bytesize, 0, 0, 0, 'reset'.bytesize, 0, 0, 'reset'].pack(FORMAT[:stat])
365
- write(req)
366
- generic_response
369
+ write_generic [REQUEST, OPCODES[:stat], 'reset'.bytesize, 0, 0, 0, 'reset'.bytesize, 0, 0, 'reset'].pack(FORMAT[:stat])
367
370
  end
368
371
 
369
372
  def cas(key)
@@ -373,15 +376,12 @@ module Dalli
373
376
  end
374
377
 
375
378
  def version
376
- req = [REQUEST, OPCODES[:version], 0, 0, 0, 0, 0, 0, 0].pack(FORMAT[:noop])
377
- write(req)
378
- generic_response
379
+ write_generic [REQUEST, OPCODES[:version], 0, 0, 0, 0, 0, 0, 0].pack(FORMAT[:noop])
379
380
  end
380
381
 
381
382
  def touch(key, ttl)
382
- req = [REQUEST, OPCODES[:touch], key.bytesize, 4, 0, 0, key.bytesize + 4, 0, 0, ttl, key].pack(FORMAT[:touch])
383
- write(req)
384
- generic_response
383
+ ttl = sanitize_ttl(ttl)
384
+ write_generic [REQUEST, OPCODES[:touch], key.bytesize, 4, 0, 0, key.bytesize + 4, 0, 0, ttl, key].pack(FORMAT[:touch])
385
385
  end
386
386
 
387
387
  # http://www.hjp.at/zettel/m/memcached_flags.rxml
@@ -434,9 +434,7 @@ module Dalli
434
434
  end
435
435
 
436
436
  def data_cas_response
437
- header = read(24)
438
- raise Dalli::NetworkError, 'No response' if !header
439
- (extras, _, status, count, _, cas) = header.unpack(CAS_HEADER)
437
+ (extras, _, status, count, _, cas) = read_header.unpack(CAS_HEADER)
440
438
  data = read(count) if count > 0
441
439
  if status == 1
442
440
  nil
@@ -463,10 +461,20 @@ module Dalli
463
461
  end
464
462
  end
465
463
 
464
+ # https://code.google.com/p/memcached/wiki/NewCommands#Standard_Protocol
465
+ # > An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a unix timestamp of an exact date.
466
+ MAX_ACCEPTABLE_EXPIRATION_INTERVAL = 30*24*60*60 # 30 days
467
+ def sanitize_ttl(ttl)
468
+ if ttl > MAX_ACCEPTABLE_EXPIRATION_INTERVAL
469
+ Dalli.logger.debug "Expiration interval too long for Memcached, converting to an expiration timestamp"
470
+ Time.now.to_i + ttl
471
+ else
472
+ ttl
473
+ end
474
+ end
475
+
466
476
  def generic_response(unpack=false)
467
- header = read(24)
468
- raise Dalli::NetworkError, 'No response' if !header
469
- (extras, _, status, count) = header.unpack(NORMAL_HEADER)
477
+ (extras, _, status, count) = read_header.unpack(NORMAL_HEADER)
470
478
  data = read(count) if count > 0
471
479
  if status == 1
472
480
  nil
@@ -484,9 +492,7 @@ module Dalli
484
492
  end
485
493
 
486
494
  def cas_response
487
- header = read(24)
488
- raise Dalli::NetworkError, 'No response' if !header
489
- (_, _, status, count, _, cas) = header.unpack(CAS_HEADER)
495
+ (_, _, status, count, _, cas) = read_header.unpack(CAS_HEADER)
490
496
  read(count) if count > 0 # this is potential data that we don't care about
491
497
  if status == 1
492
498
  nil
@@ -502,9 +508,7 @@ module Dalli
502
508
  def keyvalue_response
503
509
  hash = {}
504
510
  loop do
505
- header = read(24)
506
- raise Dalli::NetworkError, 'No response' if !header
507
- (key_length, _, body_length, _) = header.unpack(KV_HEADER)
511
+ (key_length, _, body_length, _) = read_header.unpack(KV_HEADER)
508
512
  return hash if key_length == 0
509
513
  key = read(key_length)
510
514
  value = read(body_length - key_length) if body_length - key_length > 0
@@ -515,9 +519,7 @@ module Dalli
515
519
  def multi_response
516
520
  hash = {}
517
521
  loop do
518
- header = read(24)
519
- raise Dalli::NetworkError, 'No response' if !header
520
- (key_length, _, body_length, _) = header.unpack(KV_HEADER)
522
+ (key_length, _, body_length, _) = read_header.unpack(KV_HEADER)
521
523
  return hash if key_length == 0
522
524
  flags = read(4).unpack('N')[0]
523
525
  key = read(key_length)
@@ -548,6 +550,10 @@ module Dalli
548
550
  end
549
551
  end
550
552
 
553
+ def read_header
554
+ read(24) || raise(Dalli::NetworkError, 'No response')
555
+ end
556
+
551
557
  def connect
552
558
  Dalli.logger.debug { "Dalli::Server#connect #{hostname}:#{port}" }
553
559
 
@@ -569,10 +575,6 @@ module Dalli
569
575
  [n >> 32, 0xFFFFFFFF & n]
570
576
  end
571
577
 
572
- def longlong(a, b)
573
- (a << 32) | b
574
- end
575
-
576
578
  REQUEST = 0x80
577
579
  RESPONSE = 0x81
578
580
 
@@ -661,9 +663,8 @@ module Dalli
661
663
  # negotiate
662
664
  req = [REQUEST, OPCODES[:auth_negotiation], 0, 0, 0, 0, 0, 0, 0].pack(FORMAT[:noop])
663
665
  write(req)
664
- header = read(24)
665
- raise Dalli::NetworkError, 'No response' if !header
666
- (extras, type, status, count) = header.unpack(NORMAL_HEADER)
666
+
667
+ (extras, type, status, count) = read_header.unpack(NORMAL_HEADER)
667
668
  raise Dalli::NetworkError, "Unexpected message format: #{extras} #{count}" unless extras == 0 && count > 0
668
669
  content = read(count)
669
670
  return (Dalli.logger.debug("Authentication not required/supported by server")) if status == 0x81
@@ -676,9 +677,7 @@ module Dalli
676
677
  req = [REQUEST, OPCODES[:auth_request], mechanism.bytesize, 0, 0, 0, mechanism.bytesize + msg.bytesize, 0, 0, mechanism, msg].pack(FORMAT[:auth_request])
677
678
  write(req)
678
679
 
679
- header = read(24)
680
- raise Dalli::NetworkError, 'No response' if !header
681
- (extras, type, status, count) = header.unpack(NORMAL_HEADER)
680
+ (extras, type, status, count) = read_header.unpack(NORMAL_HEADER)
682
681
  raise Dalli::NetworkError, "Unexpected message format: #{extras} #{count}" unless extras == 0 && count > 0
683
682
  content = read(count)
684
683
  return Dalli.logger.info("Dalli/SASL: #{content}") if status == 0
@@ -688,5 +687,10 @@ module Dalli
688
687
  # (step, msg) = sasl.receive('challenge', content)
689
688
  # raise Dalli::NetworkError, "Authentication failed" if sasl.failed? || step != 'response'
690
689
  end
690
+
691
+ def parse_hostname(str)
692
+ res = str.match(/\A(\[([\h:]+)\]|[^:]+)(:(\d+))?(:(\d+))?\z/)
693
+ return res[2] || res[1], res[4], res[6]
694
+ end
691
695
  end
692
696
  end
@@ -1,3 +1,3 @@
1
1
  module Dalli
2
- VERSION = '2.7.0'
2
+ VERSION = '2.7.1'
3
3
  end
@@ -16,6 +16,7 @@ module Rack
16
16
  mserv = @default_options[:memcache_server]
17
17
  mopts = @default_options.reject{|k,v| !DEFAULT_OPTIONS.include? k }
18
18
  @pool = options[:cache] || ::Dalli::Client.new(mserv, mopts)
19
+ @pool.alive!
19
20
  end
20
21
 
21
22
  def generate_sid
@@ -27,7 +28,7 @@ module Rack
27
28
 
28
29
  def get_session(env, sid)
29
30
  with_lock(env, [nil, {}]) do
30
- unless sid and session = @pool.get(sid)
31
+ unless sid and !sid.empty? and session = @pool.get(sid)
31
32
  sid, session = generate_sid, {}
32
33
  unless @pool.add(sid, session)
33
34
  raise "Session collision on '#{sid.inspect}'"
@@ -38,6 +39,7 @@ module Rack
38
39
  end
39
40
 
40
41
  def set_session(env, session_id, new_session, options)
42
+ return false unless session_id
41
43
  expiry = options[:expire_after]
42
44
  expiry = expiry.nil? ? 0 : expiry + 1
43
45
 
@@ -371,6 +371,18 @@ describe 'ActiveSupport' do
371
371
  @dalli = ActiveSupport::Cache::DalliStore.new('localhost:19122', :expires_in => 1, :namespace => 'foo', :compress => true)
372
372
  assert_equal 1, @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:expires_in]
373
373
  assert_equal 'foo', @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:namespace]
374
+ assert_equal ["localhost:19122"], @dalli.instance_variable_get(:@data).instance_variable_get(:@servers)
375
+ end
376
+ end
377
+ end
378
+
379
+ it 'handles nil server with additional options' do
380
+ with_activesupport do
381
+ memcached do
382
+ @dalli = ActiveSupport::Cache::DalliStore.new(nil, :expires_in => 1, :namespace => 'foo', :compress => true)
383
+ assert_equal 1, @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:expires_in]
384
+ assert_equal 'foo', @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:namespace]
385
+ assert_equal ["127.0.0.1:11211"], @dalli.instance_variable_get(:@data).instance_variable_get(:@servers)
374
386
  end
375
387
  end
376
388
  end
@@ -23,6 +23,16 @@ describe 'Dalli' do
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ it 'return string type for namespace attribute' do
28
+ dc = Dalli::Client.new('foo', :namespace => :wunderschoen)
29
+ assert_equal "wunderschoen", dc.send(:namespace)
30
+ dc.close
31
+
32
+ dc = Dalli::Client.new('foo', :namespace => Proc.new{:wunderschoen})
33
+ assert_equal "wunderschoen", dc.send(:namespace)
34
+ dc.close
35
+ end
26
36
  end
27
37
 
28
38
  describe 'key validation' do
@@ -42,6 +52,13 @@ describe 'Dalli' do
42
52
  end
43
53
  end
44
54
  end
55
+
56
+ it 'allow namespace to be a symbol' do
57
+ memcached(19122, '', :namespace => :wunderschoen) do |dc|
58
+ dc.set "x" * 251, 1
59
+ assert 1, dc.get("#{'x' * 200}:md5:#{Digest::MD5.hexdigest('x' * 251)}")
60
+ end
61
+ end
45
62
  end
46
63
 
47
64
  it "default to localhost:11211" do
@@ -515,6 +532,13 @@ describe 'Dalli' do
515
532
  end
516
533
  end
517
534
 
535
+ it "handle nil namespace" do
536
+ memcached do |dc|
537
+ dc = Dalli::Client.new('localhost:19122', :namespace => nil)
538
+ assert_equal 'key', dc.send(:validate_key, 'key')
539
+ end
540
+ end
541
+
518
542
  it 'truncate cache keys that are too long' do
519
543
  memcached do
520
544
  dc = Dalli::Client.new('localhost:19122', :namespace => 'some:namspace')
@@ -11,40 +11,51 @@ describe Rack::Session::Dalli do
11
11
  before do
12
12
  memcached(19129) do
13
13
  end
14
+
15
+ # test memcache connection
16
+ Rack::Session::Dalli.new(incrementor)
14
17
  end
15
18
 
16
- session_key = Rack::Session::Dalli::DEFAULT_OPTIONS[:key]
17
- session_match = /#{session_key}=([0-9a-fA-F]+);/
18
- incrementor = lambda do |env|
19
- env["rack.session"]["counter"] ||= 0
20
- env["rack.session"]["counter"] += 1
21
- Rack::Response.new(env["rack.session"].inspect).to_a
19
+ let(:session_key) { Rack::Session::Dalli::DEFAULT_OPTIONS[:key] }
20
+ let(:session_match) do
21
+ /#{session_key}=([0-9a-fA-F]+);/
22
+ end
23
+ let(:incrementor_proc) do
24
+ lambda do |env|
25
+ env["rack.session"]["counter"] ||= 0
26
+ env["rack.session"]["counter"] += 1
27
+ Rack::Response.new(env["rack.session"].inspect).to_a
28
+ end
29
+ end
30
+ let(:drop_session) do
31
+ Rack::Lint.new(proc do |env|
32
+ env['rack.session.options'][:drop] = true
33
+ incrementor_proc.call(env)
34
+ end)
35
+ end
36
+ let(:renew_session) do
37
+ Rack::Lint.new(proc do |env|
38
+ env['rack.session.options'][:renew] = true
39
+ incrementor_proc.call(env)
40
+ end)
41
+ end
42
+ let(:defer_session) do
43
+ Rack::Lint.new(proc do |env|
44
+ env['rack.session.options'][:defer] = true
45
+ incrementor_proc.call(env)
46
+ end)
47
+ end
48
+ let(:skip_session) do
49
+ Rack::Lint.new(proc do |env|
50
+ env['rack.session.options'][:skip] = true
51
+ incrementor_proc.call(env)
52
+ end)
22
53
  end
23
- drop_session = Rack::Lint.new(proc do |env|
24
- env['rack.session.options'][:drop] = true
25
- incrementor.call(env)
26
- end)
27
- renew_session = Rack::Lint.new(proc do |env|
28
- env['rack.session.options'][:renew] = true
29
- incrementor.call(env)
30
- end)
31
- defer_session = Rack::Lint.new(proc do |env|
32
- env['rack.session.options'][:defer] = true
33
- incrementor.call(env)
34
- end)
35
- skip_session = Rack::Lint.new(proc do |env|
36
- env['rack.session.options'][:skip] = true
37
- incrementor.call(env)
38
- end)
39
- incrementor = Rack::Lint.new(incrementor)
40
-
41
- # test memcache connection
42
- Rack::Session::Dalli.new(incrementor)
54
+ let(:incrementor) { Rack::Lint.new(incrementor_proc) }
43
55
 
44
56
  it "faults on no connection" do
45
57
  assert_raises Dalli::RingError do
46
- rsd = Rack::Session::Dalli.new(incrementor, :memcache_server => 'nosuchserver')
47
- rsd.pool.set('ping', '')
58
+ Rack::Session::Dalli.new(incrementor, :memcache_server => 'nosuchserver')
48
59
  end
49
60
  end
50
61
 
@@ -104,6 +115,15 @@ describe Rack::Session::Dalli do
104
115
  refute_match(/#{bad_cookie}/, cookie)
105
116
  end
106
117
 
118
+ it "survives nonexistant blank cookies" do
119
+ bad_cookie = "rack.session="
120
+ rsd = Rack::Session::Dalli.new(incrementor)
121
+ res = Rack::MockRequest.new(rsd).
122
+ get("/", "HTTP_COOKIE" => bad_cookie)
123
+ cookie = res["Set-Cookie"][session_match]
124
+ refute_match(/#{bad_cookie}$/, cookie)
125
+ end
126
+
107
127
  it "maintains freshness" do
108
128
  rsd = Rack::Session::Dalli.new(incrementor, :expire_after => 3)
109
129
  res = Rack::MockRequest.new(rsd).get('/')
@@ -0,0 +1,80 @@
1
+ require 'helper'
2
+
3
+ describe Dalli::Server do
4
+ describe 'hostname parsing' do
5
+ it 'handles no port or weight' do
6
+ s = Dalli::Server.new('localhost')
7
+ assert_equal 'localhost', s.hostname
8
+ assert_equal 11211, s.port
9
+ assert_equal 1, s.weight
10
+ end
11
+
12
+ it 'handles a port, but no weight' do
13
+ s = Dalli::Server.new('localhost:11212')
14
+ assert_equal 'localhost', s.hostname
15
+ assert_equal 11212, s.port
16
+ assert_equal 1, s.weight
17
+ end
18
+
19
+ it 'handles a port and a weight' do
20
+ s = Dalli::Server.new('localhost:11212:2')
21
+ assert_equal 'localhost', s.hostname
22
+ assert_equal 11212, s.port
23
+ assert_equal 2, s.weight
24
+ end
25
+
26
+ it 'handles ipv4 addresses' do
27
+ s = Dalli::Server.new('127.0.0.1')
28
+ assert_equal '127.0.0.1', s.hostname
29
+ assert_equal 11211, s.port
30
+ assert_equal 1, s.weight
31
+ end
32
+
33
+ it 'handles ipv6 addresses' do
34
+ s = Dalli::Server.new('[::1]')
35
+ assert_equal '::1', s.hostname
36
+ assert_equal 11211, s.port
37
+ assert_equal 1, s.weight
38
+ end
39
+
40
+ it 'handles ipv6 addresses with port' do
41
+ s = Dalli::Server.new('[::1]:11212')
42
+ assert_equal '::1', s.hostname
43
+ assert_equal 11212, s.port
44
+ assert_equal 1, s.weight
45
+ end
46
+
47
+ it 'handles ipv6 addresses with port and weight' do
48
+ s = Dalli::Server.new('[::1]:11212:2')
49
+ assert_equal '::1', s.hostname
50
+ assert_equal 11212, s.port
51
+ assert_equal 2, s.weight
52
+ end
53
+
54
+ it 'handles a FQDN' do
55
+ s = Dalli::Server.new('my.fqdn.com')
56
+ assert_equal 'my.fqdn.com', s.hostname
57
+ assert_equal 11211, s.port
58
+ assert_equal 1, s.weight
59
+ end
60
+
61
+ it 'handles a FQDN with port and weight' do
62
+ s = Dalli::Server.new('my.fqdn.com:11212:2')
63
+ assert_equal 'my.fqdn.com', s.hostname
64
+ assert_equal 11212, s.port
65
+ assert_equal 2, s.weight
66
+ end
67
+ end
68
+
69
+ describe 'ttl translation' do
70
+ it 'does not translate ttls under 30 days' do
71
+ s = Dalli::Server.new('localhost')
72
+ assert_equal s.send(:sanitize_ttl, 30*24*60*60), 30*24*60*60
73
+ end
74
+
75
+ it 'translates ttls over 30 days into timestamps' do
76
+ s = Dalli::Server.new('localhost')
77
+ assert_equal s.send(:sanitize_ttl, 30*24*60*60 + 1), Time.now.to_i + 30*24*60*60+1
78
+ end
79
+ end
80
+ end
metadata CHANGED
@@ -1,65 +1,73 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dalli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-07 00:00:00.000000000 Z
11
+ date: 2014-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.2.0
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mocha
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3'
47
+ version: '4'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3'
54
+ version: '4'
55
55
  description: High performance memcached client for Ruby
56
56
  email: mperham@gmail.com
57
57
  executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
60
  files:
61
+ - Gemfile
62
+ - History.md
63
+ - LICENSE
64
+ - Performance.md
65
+ - README.md
66
+ - Rakefile
67
+ - dalli.gemspec
61
68
  - lib/action_dispatch/middleware/session/dalli_store.rb
62
69
  - lib/active_support/cache/dalli_store.rb
70
+ - lib/dalli.rb
63
71
  - lib/dalli/cas/client.rb
64
72
  - lib/dalli/client.rb
65
73
  - lib/dalli/compressor.rb
@@ -69,15 +77,7 @@ files:
69
77
  - lib/dalli/server.rb
70
78
  - lib/dalli/socket.rb
71
79
  - lib/dalli/version.rb
72
- - lib/dalli.rb
73
80
  - lib/rack/session/dalli.rb
74
- - LICENSE
75
- - README.md
76
- - History.md
77
- - Rakefile
78
- - Gemfile
79
- - dalli.gemspec
80
- - Performance.md
81
81
  - test/benchmark_test.rb
82
82
  - test/helper.rb
83
83
  - test/memcached_mock.rb
@@ -93,28 +93,29 @@ files:
93
93
  - test/test_ring.rb
94
94
  - test/test_sasl.rb
95
95
  - test/test_serializer.rb
96
+ - test/test_server.rb
96
97
  homepage: http://github.com/mperham/dalli
97
98
  licenses:
98
99
  - MIT
99
100
  metadata: {}
100
101
  post_install_message:
101
102
  rdoc_options:
102
- - --charset=UTF-8
103
+ - "--charset=UTF-8"
103
104
  require_paths:
104
105
  - lib
105
106
  required_ruby_version: !ruby/object:Gem::Requirement
106
107
  requirements:
107
- - - '>='
108
+ - - ">="
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  requirements:
112
- - - '>='
113
+ - - ">="
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
117
  rubyforge_project:
117
- rubygems_version: 2.0.14
118
+ rubygems_version: 2.2.2
118
119
  signing_key:
119
120
  specification_version: 4
120
121
  summary: High performance memcached client for Ruby
@@ -134,3 +135,4 @@ test_files:
134
135
  - test/test_ring.rb
135
136
  - test/test_sasl.rb
136
137
  - test/test_serializer.rb
138
+ - test/test_server.rb