dalli 0.9.0 → 0.9.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.
- data/Gemfile +5 -1
- data/History.md +14 -0
- data/Performance.md +19 -18
- data/README.md +14 -1
- data/TODO.md +6 -0
- data/dalli.gemspec +5 -2
- data/lib/dalli.rb +10 -4
- data/lib/dalli/client.rb +58 -12
- data/lib/dalli/ring.rb +12 -8
- data/lib/dalli/sasl/anonymous.rb +14 -0
- data/lib/dalli/sasl/base.rb +89 -0
- data/lib/dalli/sasl/base64.rb +14 -0
- data/lib/dalli/sasl/digest_md5.rb +175 -0
- data/lib/dalli/sasl/plain.rb +18 -0
- data/lib/dalli/server.rb +124 -12
- data/lib/dalli/version.rb +1 -1
- data/test/helper.rb +8 -0
- data/test/memcached_mock.rb +49 -3
- data/test/test_active_support.rb +60 -47
- data/test/test_benchmark.rb +79 -76
- data/test/test_dalli.rb +230 -69
- data/test/test_network.rb +5 -9
- metadata +29 -9
data/test/helper.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
|
3
|
+
# require 'simplecov-html'
|
4
|
+
# SimpleCov.start
|
5
|
+
|
2
6
|
require 'test/unit'
|
3
7
|
require 'shoulda'
|
8
|
+
require 'memcached_mock'
|
9
|
+
require 'mocha'
|
4
10
|
|
5
11
|
require 'dalli'
|
6
12
|
|
7
13
|
class Test::Unit::TestCase
|
14
|
+
include MemcachedMock::Helper
|
15
|
+
|
8
16
|
def assert_error(error, regexp=nil, &block)
|
9
17
|
ex = assert_raise(error, &block)
|
10
18
|
assert_match(regexp, ex.message, "#{ex.class.name}: #{ex.message}\n#{ex.backtrace.join("\n\t")}")
|
data/test/memcached_mock.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
require "socket"
|
2
2
|
|
3
3
|
module MemcachedMock
|
4
|
-
def self.start(port=
|
4
|
+
def self.start(port=19123, &block)
|
5
5
|
server = TCPServer.new("localhost", port)
|
6
6
|
session = server.accept
|
7
7
|
block.call session
|
8
8
|
end
|
9
9
|
|
10
|
-
def self.delayed_start(port=
|
10
|
+
def self.delayed_start(port=19123, wait=1, &block)
|
11
11
|
server = TCPServer.new("localhost", port)
|
12
12
|
sleep wait
|
13
|
-
# session = server.accept
|
14
13
|
block.call server
|
15
14
|
end
|
16
15
|
|
@@ -41,5 +40,52 @@ module MemcachedMock
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
43
|
+
|
44
|
+
PATHS = %w(
|
45
|
+
/usr/local/bin/
|
46
|
+
/opt/local/bin/
|
47
|
+
/usr/bin/
|
48
|
+
)
|
49
|
+
|
50
|
+
def find_memcached
|
51
|
+
output = `memcached -h | head -1`.strip
|
52
|
+
if output && output =~ /^memcached (\d.\d.\d+)/ && $1 > '1.4'
|
53
|
+
return (puts "Found #{output} in PATH"; '')
|
54
|
+
end
|
55
|
+
PATHS.each do |path|
|
56
|
+
output = `memcached -h | head -1`.strip
|
57
|
+
if output && output =~ /^memcached (\d\.\d\.\d+)/ && $1 > '1.4'
|
58
|
+
return (puts "Found #{output} in #{path}"; path)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
raise Errno::ENOENT, "Unable to find memcached 1.4+ locally"
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def memcached(port=19122, args='')
|
67
|
+
Memcached.path ||= find_memcached
|
68
|
+
cmd = "#{Memcached.path}memcached #{args} -p #{port}"
|
69
|
+
# puts "Starting: #{cmd}..."
|
70
|
+
pid = IO.popen(cmd).pid
|
71
|
+
begin
|
72
|
+
sleep 0.3
|
73
|
+
yield Dalli::Client.new(["localhost:#{port}", "127.0.0.1:#{port}"])
|
74
|
+
ensure
|
75
|
+
begin
|
76
|
+
Process.kill("TERM", pid)
|
77
|
+
Process.wait(pid)
|
78
|
+
rescue Errno::ECHILD
|
79
|
+
# the memcached_mock forks will try to run this at_exit block also
|
80
|
+
# but since they are not the parent process, will get an ECHILD error.
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module Memcached
|
88
|
+
class << self
|
89
|
+
attr_accessor :path
|
44
90
|
end
|
45
91
|
end
|
data/test/test_active_support.rb
CHANGED
@@ -4,70 +4,83 @@ require 'active_support/cache/dalli_store'
|
|
4
4
|
|
5
5
|
class TestDalli < Test::Unit::TestCase
|
6
6
|
context 'activesupport caching' do
|
7
|
-
setup do
|
8
|
-
@dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:11211', :expires_in => 10.seconds)
|
9
|
-
@mc = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost:11211', :expires_in => 10.seconds, :namespace => 'a')
|
10
|
-
@dalli.clear
|
11
|
-
end
|
12
7
|
|
13
8
|
should 'support fetch' do
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
memcached do
|
10
|
+
connect
|
11
|
+
dvalue = @mc.fetch('some key with spaces', :expires_in => 1.second) { 123 }
|
12
|
+
mvalue = @dalli.fetch('some other key with spaces', :expires_in => 1.second) { 123 }
|
13
|
+
assert_equal mvalue, dvalue
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
o = Object.new
|
16
|
+
o.instance_variable_set :@foo, 'bar'
|
17
|
+
dvalue = @mc.fetch(rand_key, :raw => true) { o }
|
18
|
+
mvalue = @dalli.fetch(rand_key, :raw => true) { o }
|
19
|
+
assert_equal mvalue, dvalue
|
20
|
+
assert_equal o, dvalue
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
dvalue = @mc.fetch(rand_key) { o }
|
23
|
+
mvalue = @dalli.fetch(rand_key) { o }
|
24
|
+
assert_equal mvalue, dvalue
|
25
|
+
assert_equal o, dvalue
|
26
|
+
end
|
29
27
|
end
|
30
28
|
|
31
29
|
should 'support read_multi' do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
memcached do
|
31
|
+
connect
|
32
|
+
x = rand_key
|
33
|
+
y = rand_key
|
34
|
+
assert_equal({}, @mc.read_multi(x, y))
|
35
|
+
assert_equal({}, @dalli.read_multi(x, y))
|
36
|
+
@dalli.write(x, '123')
|
37
|
+
@dalli.write(y, 123)
|
38
|
+
@mc.write(x, '123')
|
39
|
+
@mc.write(y, 123)
|
40
|
+
assert_equal({ x => '123', y => 123 }, @dalli.read_multi(x, y))
|
41
|
+
assert_equal({ x => '123', y => 123 }, @mc.read_multi(x, y))
|
42
|
+
end
|
42
43
|
end
|
43
44
|
|
44
45
|
should 'support read, write and delete' do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
memcached do
|
47
|
+
connect
|
48
|
+
x = rand_key
|
49
|
+
y = rand_key
|
50
|
+
assert_nil @mc.read(x)
|
51
|
+
assert_nil @dalli.read(y)
|
52
|
+
mres = @mc.write(x, 123)
|
53
|
+
dres = @dalli.write(y, 123)
|
54
|
+
assert_equal mres, dres
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
mres = @mc.read(x)
|
57
|
+
dres = @dalli.read(y)
|
58
|
+
assert_equal mres, dres
|
59
|
+
assert_equal 123, dres
|
57
60
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
mres = @mc.delete(x)
|
62
|
+
dres = @dalli.delete(y)
|
63
|
+
assert_equal mres, dres
|
64
|
+
assert_equal true, dres
|
65
|
+
end
|
62
66
|
end
|
63
67
|
|
64
68
|
should 'support other esoteric commands' do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
+
memcached do
|
70
|
+
connect
|
71
|
+
ms = @mc.stats
|
72
|
+
ds = @dalli.stats
|
73
|
+
assert_equal ms.keys.sort, ds.keys.sort
|
74
|
+
assert_equal ms[ms.keys.first].keys.sort, ds[ds.keys.first].keys.sort
|
75
|
+
end
|
69
76
|
end
|
70
77
|
end
|
78
|
+
|
79
|
+
def connect
|
80
|
+
@dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds)
|
81
|
+
@mc = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'a')
|
82
|
+
@dalli.clear
|
83
|
+
end
|
71
84
|
|
72
85
|
def rand_key
|
73
86
|
rand(1_000_000_000)
|
data/test/test_benchmark.rb
CHANGED
@@ -10,7 +10,7 @@ class TestBenchmark < Test::Unit::TestCase
|
|
10
10
|
@value = []
|
11
11
|
@marshalled = Marshal.dump(@value)
|
12
12
|
|
13
|
-
@servers = ['127.0.0.1:
|
13
|
+
@servers = ['127.0.0.1:19122', 'localhost:19122']
|
14
14
|
@key1 = "Short"
|
15
15
|
@key2 = "Sym1-2-3::45"*8
|
16
16
|
@key3 = "Long"*40
|
@@ -21,97 +21,100 @@ class TestBenchmark < Test::Unit::TestCase
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_benchmark
|
24
|
-
|
24
|
+
memcached do
|
25
|
+
|
26
|
+
Benchmark.bm(31) do |x|
|
25
27
|
|
26
|
-
|
28
|
+
n = 2500
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
@m = Dalli::Client.new(@servers, :marshal => false)
|
31
|
+
x.report("set:plain:dalli") do
|
32
|
+
n.times do
|
33
|
+
@m.set @key1, @marshalled
|
34
|
+
@m.set @key2, @marshalled
|
35
|
+
@m.set @key3, @marshalled
|
36
|
+
@m.set @key1, @marshalled
|
37
|
+
@m.set @key2, @marshalled
|
38
|
+
@m.set @key3, @marshalled
|
39
|
+
end
|
37
40
|
end
|
38
|
-
end
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
42
|
+
@m = Dalli::Client.new(@servers)
|
43
|
+
x.report("set:ruby:dalli") do
|
44
|
+
n.times do
|
45
|
+
@m.set @key1, @value
|
46
|
+
@m.set @key2, @value
|
47
|
+
@m.set @key3, @value
|
48
|
+
@m.set @key1, @value
|
49
|
+
@m.set @key2, @value
|
50
|
+
@m.set @key3, @value
|
51
|
+
end
|
49
52
|
end
|
50
|
-
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
@m = Dalli::Client.new(@servers, :marshal => false)
|
55
|
+
x.report("get:plain:dalli") do
|
56
|
+
n.times do
|
57
|
+
@m.get @key1
|
58
|
+
@m.get @key2
|
59
|
+
@m.get @key3
|
60
|
+
@m.get @key1
|
61
|
+
@m.get @key2
|
62
|
+
@m.get @key3
|
63
|
+
end
|
61
64
|
end
|
62
|
-
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
@m = Dalli::Client.new(@servers)
|
67
|
+
x.report("get:ruby:dalli") do
|
68
|
+
n.times do
|
69
|
+
@m.get @key1
|
70
|
+
@m.get @key2
|
71
|
+
@m.get @key3
|
72
|
+
@m.get @key1
|
73
|
+
@m.get @key2
|
74
|
+
@m.get @key3
|
75
|
+
end
|
73
76
|
end
|
74
|
-
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
@m = Dalli::Client.new(@servers)
|
79
|
+
x.report("multiget:ruby:dalli") do
|
80
|
+
n.times do
|
81
|
+
# We don't use the keys array because splat is slow
|
82
|
+
@m.get_multi @key1, @key2, @key3, @key4, @key5, @key6
|
83
|
+
end
|
81
84
|
end
|
82
|
-
end
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
86
|
+
@m = Dalli::Client.new(@servers)
|
87
|
+
x.report("missing:ruby:dalli") do
|
88
|
+
n.times do
|
89
|
+
begin @m.delete @key1; rescue; end
|
90
|
+
begin @m.get @key1; rescue; end
|
91
|
+
begin @m.delete @key2; rescue; end
|
92
|
+
begin @m.get @key2; rescue; end
|
93
|
+
begin @m.delete @key3; rescue; end
|
94
|
+
begin @m.get @key3; rescue; end
|
95
|
+
end
|
93
96
|
end
|
94
|
-
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
98
|
+
@m = Dalli::Client.new(@servers)
|
99
|
+
x.report("mixed:ruby:dalli") do
|
100
|
+
n.times do
|
101
|
+
@m.set @key1, @value
|
102
|
+
@m.set @key2, @value
|
103
|
+
@m.set @key3, @value
|
104
|
+
@m.get @key1
|
105
|
+
@m.get @key2
|
106
|
+
@m.get @key3
|
107
|
+
@m.set @key1, @value
|
108
|
+
@m.get @key1
|
109
|
+
@m.set @key2, @value
|
110
|
+
@m.get @key2
|
111
|
+
@m.set @key3, @value
|
112
|
+
@m.get @key3
|
113
|
+
end
|
111
114
|
end
|
112
|
-
end
|
113
115
|
|
114
|
-
|
116
|
+
assert true
|
117
|
+
end
|
115
118
|
end
|
116
119
|
|
117
120
|
end
|
data/test/test_dalli.rb
CHANGED
@@ -1,97 +1,258 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'memcached_mock'
|
2
3
|
|
3
4
|
class TestDalli < Test::Unit::TestCase
|
4
5
|
context 'using a live server' do
|
5
|
-
setup do
|
6
|
-
begin
|
7
|
-
TCPSocket.new('localhost', 11211)
|
8
|
-
rescue => ex
|
9
|
-
$skip = true
|
10
|
-
puts "Skipping live test as memcached is not running at localhost:11211. Start it with 'memcached -d'"
|
11
|
-
end
|
12
|
-
end
|
13
6
|
|
14
7
|
should "support huge get/set" do
|
15
|
-
|
16
|
-
|
17
|
-
dc.flush
|
8
|
+
memcached do |dc|
|
9
|
+
dc.flush
|
18
10
|
|
19
|
-
|
20
|
-
|
11
|
+
val1 = "1234567890"*105000
|
12
|
+
assert_error Dalli::DalliError, /too large/ do
|
13
|
+
dc.set('a', val1)
|
14
|
+
val2 = dc.get('a')
|
15
|
+
assert_equal val1, val2
|
16
|
+
end
|
17
|
+
|
18
|
+
val1 = "1234567890"*100000
|
21
19
|
dc.set('a', val1)
|
22
20
|
val2 = dc.get('a')
|
23
21
|
assert_equal val1, val2
|
24
22
|
end
|
23
|
+
end
|
24
|
+
|
25
|
+
should "support the fetch operation" do
|
26
|
+
memcached do |dc|
|
27
|
+
dc.flush
|
28
|
+
|
29
|
+
expected = { 'blah' => 'blerg!' }
|
30
|
+
executed = false
|
31
|
+
value = dc.fetch('fetch_key') do
|
32
|
+
executed = true
|
33
|
+
expected
|
34
|
+
end
|
35
|
+
assert_equal expected, value
|
36
|
+
assert_equal true, executed
|
37
|
+
|
38
|
+
executed = false
|
39
|
+
value = dc.fetch('fetch_key') do
|
40
|
+
executed = true
|
41
|
+
expected
|
42
|
+
end
|
43
|
+
assert_equal expected, value
|
44
|
+
assert_equal false, executed
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
should "support the cas operation" do
|
49
|
+
memcached do |dc|
|
50
|
+
dc.flush
|
51
|
+
|
52
|
+
expected = { 'blah' => 'blerg!' }
|
25
53
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
54
|
+
resp = dc.cas('cas_key') do |value|
|
55
|
+
fail('Value should not exist')
|
56
|
+
end
|
57
|
+
assert_nil resp
|
58
|
+
|
59
|
+
mutated = { 'blah' => 'foo!' }
|
60
|
+
dc.set('cas_key', expected)
|
61
|
+
resp = dc.cas('cas_key') do |value|
|
62
|
+
assert_equal expected, value
|
63
|
+
mutated
|
64
|
+
end
|
65
|
+
assert_equal true, resp
|
66
|
+
|
67
|
+
resp = dc.get('cas_key')
|
68
|
+
assert_equal mutated, resp
|
69
|
+
|
70
|
+
# TODO Need to verify failure when value is mutated between get and add.
|
71
|
+
end
|
30
72
|
end
|
31
73
|
|
32
74
|
should "support multi-get" do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
75
|
+
memcached do |dc|
|
76
|
+
dc.flush
|
77
|
+
resp = dc.get_multi(%w(a b c d e f))
|
78
|
+
assert_equal({}, resp)
|
79
|
+
|
80
|
+
dc.set('a', 'foo')
|
81
|
+
dc.set('b', 123)
|
82
|
+
dc.set('c', %w(a b c))
|
83
|
+
resp = dc.get_multi(%w(a b c d e f))
|
84
|
+
assert_equal({ 'a' => 'foo', 'b' => 123, 'c' => %w(a b c) }, resp)
|
85
|
+
end
|
44
86
|
end
|
45
87
|
|
46
|
-
should "
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
dc.
|
88
|
+
should "support incr/decr operations" do
|
89
|
+
memcached do |dc|
|
90
|
+
dc.flush
|
91
|
+
|
92
|
+
resp = dc.decr('counter', 100, 5, 0)
|
93
|
+
assert_equal 0, resp
|
94
|
+
|
95
|
+
resp = dc.decr('counter', 10)
|
96
|
+
assert_equal 0, resp
|
97
|
+
|
98
|
+
resp = dc.incr('counter', 10)
|
99
|
+
assert_equal 10, resp
|
100
|
+
|
101
|
+
current = 10
|
102
|
+
100.times do |x|
|
103
|
+
resp = dc.incr('counter', 10)
|
104
|
+
assert_equal current + ((x+1)*10), resp
|
105
|
+
end
|
106
|
+
|
107
|
+
resp = dc.decr('10billion', 0, 5, 10)
|
108
|
+
# go over the 32-bit mark to verify proper (un)packing
|
109
|
+
resp = dc.incr('10billion', 10_000_000_000)
|
110
|
+
assert_equal 10_000_000_010, resp
|
111
|
+
|
112
|
+
resp = dc.decr('10billion', 1)
|
113
|
+
assert_equal 10_000_000_009, resp
|
114
|
+
|
115
|
+
resp = dc.decr('10billion', 0)
|
116
|
+
assert_equal 10_000_000_009, resp
|
117
|
+
|
118
|
+
resp = dc.incr('10billion', 0)
|
119
|
+
assert_equal 10_000_000_009, resp
|
120
|
+
|
121
|
+
assert_nil dc.incr('DNE', 10)
|
122
|
+
assert_nil dc.decr('DNE', 10)
|
123
|
+
|
124
|
+
resp = dc.incr('big', 100, 5, 0xFFFFFFFFFFFFFFFE)
|
125
|
+
assert_equal 0xFFFFFFFFFFFFFFFE, resp
|
126
|
+
resp = dc.incr('big', 1)
|
127
|
+
assert_equal 0xFFFFFFFFFFFFFFFF, resp
|
128
|
+
|
129
|
+
# rollover the 64-bit value, we'll get something undefined.
|
130
|
+
resp = dc.incr('big', 1)
|
131
|
+
assert_not_equal 0x10000000000000000, resp
|
68
132
|
end
|
133
|
+
end
|
134
|
+
|
135
|
+
should "pass a simple smoke test" do
|
136
|
+
memcached do |dc|
|
137
|
+
resp = dc.flush
|
138
|
+
assert_not_nil resp
|
139
|
+
assert_equal [true, true], resp
|
140
|
+
|
141
|
+
resp = dc.get('123')
|
142
|
+
assert_equal nil, resp
|
143
|
+
|
144
|
+
resp = dc.set('123', 'xyz')
|
145
|
+
assert_equal true, resp
|
146
|
+
|
147
|
+
resp = dc.get('123')
|
148
|
+
assert_equal 'xyz', resp
|
149
|
+
|
150
|
+
resp = dc.set('123', 'abc')
|
151
|
+
assert_equal true, resp
|
152
|
+
|
153
|
+
assert_raises Dalli::DalliError do
|
154
|
+
dc.prepend('123', '0')
|
155
|
+
end
|
156
|
+
|
157
|
+
assert_raises Dalli::DalliError do
|
158
|
+
dc.append('123', '0')
|
159
|
+
end
|
160
|
+
|
161
|
+
resp = dc.get('123')
|
162
|
+
assert_equal 'abc', resp
|
163
|
+
dc.close
|
164
|
+
dc = nil
|
165
|
+
|
166
|
+
dc = Dalli::Client.new('localhost:19122', :marshal => false)
|
167
|
+
|
168
|
+
resp = dc.set('456', 'xyz')
|
169
|
+
assert_equal true, resp
|
170
|
+
|
171
|
+
resp = dc.prepend '456', '0'
|
172
|
+
assert_equal true, resp
|
69
173
|
|
70
|
-
|
71
|
-
|
174
|
+
resp = dc.append '456', '9'
|
175
|
+
assert_equal true, resp
|
176
|
+
|
177
|
+
resp = dc.get('456')
|
178
|
+
assert_equal '0xyz9', resp
|
179
|
+
|
180
|
+
resp = dc.stats
|
181
|
+
assert_equal Hash, resp.class
|
72
182
|
end
|
183
|
+
end
|
184
|
+
|
185
|
+
should "support multithreaded access" do
|
186
|
+
memcached(11211) do |cache|
|
187
|
+
cache.flush
|
188
|
+
workers = []
|
73
189
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
190
|
+
cache.set('f', 'zzz')
|
191
|
+
assert_equal true, (cache.cas('f') do |value|
|
192
|
+
value << 'z'
|
193
|
+
end)
|
194
|
+
assert_equal 'zzzz', cache.get('f')
|
78
195
|
|
79
|
-
|
196
|
+
# Have a bunch of threads perform a bunch of operations at the same time.
|
197
|
+
# Verify the result of each operation to ensure the request and response
|
198
|
+
# are not intermingled between threads.
|
199
|
+
10.times do
|
200
|
+
workers << Thread.new do
|
201
|
+
100.times do
|
202
|
+
cache.set('a', 9)
|
203
|
+
cache.set('b', 11)
|
204
|
+
inc = cache.incr('cat', 10, 0, 10)
|
205
|
+
cache.set('f', 'zzz')
|
206
|
+
assert_not_nil(cache.cas('f') do |value|
|
207
|
+
value << 'z'
|
208
|
+
end)
|
209
|
+
assert_equal false, cache.add('a', 11)
|
210
|
+
assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
|
211
|
+
inc = cache.incr('cat', 10)
|
212
|
+
assert_equal 0, inc % 5
|
213
|
+
dec = cache.decr('cat', 5)
|
214
|
+
assert_equal 11, cache.get('b')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
80
218
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
assert_equal true, resp
|
219
|
+
workers.each { |w| w.join }
|
220
|
+
cache.flush
|
221
|
+
end
|
222
|
+
end
|
86
223
|
|
87
|
-
|
88
|
-
|
224
|
+
should 'gracefully handle authentication failures' do
|
225
|
+
memcached(19122, '-S') do |dc|
|
226
|
+
assert_raise Dalli::DalliError, /32/ do
|
227
|
+
dc.set('abc', 123)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
89
231
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
232
|
+
# OSX: Create a SASL user for the memcached application like so:
|
233
|
+
#
|
234
|
+
# saslpasswd2 -a memcached -c testuser
|
235
|
+
#
|
236
|
+
# with password 'testtest'
|
237
|
+
context 'in an authenticated environment' do
|
238
|
+
setup do
|
239
|
+
ENV['MEMCACHE_USERNAME'] = 'testuser'
|
240
|
+
ENV['MEMCACHE_PASSWORD'] = 'testtest'
|
241
|
+
end
|
242
|
+
|
243
|
+
teardown do
|
244
|
+
ENV['MEMCACHE_USERNAME'] = nil
|
245
|
+
ENV['MEMCACHE_PASSWORD'] = nil
|
246
|
+
end
|
247
|
+
|
248
|
+
should 'support SASL authentication' do
|
249
|
+
memcached(19121, '-S') do |dc|
|
250
|
+
assert_equal true, dc.set('abc', 123)
|
251
|
+
assert_equal 123, dc.get('abc')
|
252
|
+
assert_equal({"localhost:19121"=>{}}, dc.stats)
|
253
|
+
end
|
254
|
+
end
|
95
255
|
end
|
256
|
+
|
96
257
|
end
|
97
258
|
end
|