dalli 2.7.4 → 2.7.5
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 +4 -4
- data/Gemfile +0 -7
- data/History.md +15 -0
- data/LICENSE +1 -1
- data/README.md +14 -6
- data/lib/active_support/cache/dalli_store.rb +39 -9
- data/lib/dalli/client.rb +40 -27
- data/lib/dalli/server.rb +33 -18
- data/lib/dalli/socket.rb +14 -4
- data/lib/dalli/version.rb +1 -1
- metadata +79 -43
- data/Performance.md +0 -42
- data/Rakefile +0 -43
- data/dalli.gemspec +0 -29
- data/test/benchmark_test.rb +0 -243
- data/test/helper.rb +0 -56
- data/test/memcached_mock.rb +0 -201
- data/test/sasl/memcached.conf +0 -1
- data/test/sasl/sasldb +0 -1
- data/test/test_active_support.rb +0 -541
- data/test/test_cas_client.rb +0 -107
- data/test/test_compressor.rb +0 -52
- data/test/test_dalli.rb +0 -682
- data/test/test_encoding.rb +0 -32
- data/test/test_failover.rb +0 -137
- data/test/test_network.rb +0 -64
- data/test/test_rack_session.rb +0 -341
- data/test/test_ring.rb +0 -85
- data/test/test_sasl.rb +0 -105
- data/test/test_serializer.rb +0 -29
- data/test/test_server.rb +0 -110
data/test/test_cas_client.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'memcached_mock'
|
3
|
-
|
4
|
-
describe 'Dalli::Cas::Client' do
|
5
|
-
describe 'using a live server' do
|
6
|
-
it 'supports get with CAS' do
|
7
|
-
memcached_cas_persistent do |dc|
|
8
|
-
dc.flush
|
9
|
-
|
10
|
-
expected = { 'blah' => 'blerg!' }
|
11
|
-
get_block_called = false
|
12
|
-
stored_value = stored_cas = nil
|
13
|
-
# Validate call-with-block
|
14
|
-
dc.get_cas('gets_key') do |v, cas|
|
15
|
-
get_block_called = true
|
16
|
-
stored_value = v
|
17
|
-
stored_cas = cas
|
18
|
-
end
|
19
|
-
assert get_block_called
|
20
|
-
assert_nil stored_value
|
21
|
-
|
22
|
-
dc.set('gets_key', expected)
|
23
|
-
|
24
|
-
# Validate call-with-return-value
|
25
|
-
stored_value, stored_cas = dc.get_cas('gets_key')
|
26
|
-
assert_equal stored_value, expected
|
27
|
-
assert(stored_cas != 0)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'supports multi-get with CAS' do
|
32
|
-
memcached_cas_persistent do |dc|
|
33
|
-
dc.close
|
34
|
-
dc.flush
|
35
|
-
|
36
|
-
expected_hash = {'a' => 'foo', 'b' => 123}
|
37
|
-
expected_hash.each_pair do |k, v|
|
38
|
-
dc.set(k, v)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Invocation without block
|
42
|
-
resp = dc.get_multi_cas(%w(a b c d e f))
|
43
|
-
resp.each_pair do |k, data|
|
44
|
-
value, cas = [data.first, data[1]]
|
45
|
-
assert_equal expected_hash[k], value
|
46
|
-
assert(cas && cas != 0)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Invocation with block
|
50
|
-
dc.get_multi_cas(%w(a b c d e f)) do |k, data|
|
51
|
-
value, cas = [data.first, data[1]]
|
52
|
-
assert_equal expected_hash[k], value
|
53
|
-
assert(cas && cas != 0)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'supports replace-with-CAS operation' do
|
59
|
-
memcached_cas_persistent do |dc|
|
60
|
-
dc.flush
|
61
|
-
cas = dc.set('key', 'value')
|
62
|
-
|
63
|
-
# Accepts CAS, replaces, and returns new CAS
|
64
|
-
cas = dc.replace_cas('key', 'value2', cas)
|
65
|
-
assert cas.is_a?(Integer)
|
66
|
-
|
67
|
-
assert_equal 'value2', dc.get('key')
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'supports delete with CAS' do
|
72
|
-
memcached_cas_persistent do |dc|
|
73
|
-
cas = dc.set('some_key', 'some_value')
|
74
|
-
dc.delete_cas('some_key', cas)
|
75
|
-
assert_nil dc.get('some_key')
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'handles CAS round-trip operations' do
|
80
|
-
memcached_cas_persistent do |dc|
|
81
|
-
dc.flush
|
82
|
-
|
83
|
-
expected = {'blah' => 'blerg!'}
|
84
|
-
dc.set('some_key', expected)
|
85
|
-
|
86
|
-
value, cas = dc.get_cas('some_key')
|
87
|
-
assert_equal value, expected
|
88
|
-
assert(!cas.nil? && cas != 0)
|
89
|
-
|
90
|
-
# Set operation, first with wrong then with correct CAS
|
91
|
-
expected = {'blah' => 'set succeeded'}
|
92
|
-
assert(dc.set_cas('some_key', expected, cas+1) == false)
|
93
|
-
assert op_addset_succeeds(cas = dc.set_cas('some_key', expected, cas))
|
94
|
-
|
95
|
-
# Replace operation, first with wrong then with correct CAS
|
96
|
-
expected = {'blah' => 'replace succeeded'}
|
97
|
-
assert(dc.replace_cas('some_key', expected, cas+1) == false)
|
98
|
-
assert op_addset_succeeds(cas = dc.replace_cas('some_key', expected, cas))
|
99
|
-
|
100
|
-
# Delete operation, first with wrong then with correct CAS
|
101
|
-
assert(dc.delete_cas('some_key', cas+1) == false)
|
102
|
-
assert dc.delete_cas('some_key', cas)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
data/test/test_compressor.rb
DELETED
@@ -1,52 +0,0 @@
|
|
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
|
-
it 'default to Dalli::Compressor' do
|
19
|
-
memcached(29199) do |dc|
|
20
|
-
dc.set 1,2
|
21
|
-
assert_equal Dalli::Compressor, dc.instance_variable_get('@ring').servers.first.compressor
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'support a custom compressor' do
|
26
|
-
memcached(29199) do |dc|
|
27
|
-
memcache = Dalli::Client.new('127.0.0.1:29199', :compressor => NoopCompressor)
|
28
|
-
memcache.set 1,2
|
29
|
-
begin
|
30
|
-
assert_equal NoopCompressor, memcache.instance_variable_get('@ring').servers.first.compressor
|
31
|
-
|
32
|
-
memcached(19127) do |newdc|
|
33
|
-
assert newdc.set("string-test", "a test string")
|
34
|
-
assert_equal("a test string", newdc.get("string-test"))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe 'GzipCompressor' do
|
42
|
-
|
43
|
-
it 'compress and uncompress data using Zlib::GzipWriter/Reader' do
|
44
|
-
memcached(19127,nil,{:compress=>true,:compressor=>Dalli::GzipCompressor}) do |dc|
|
45
|
-
data = (0...1025).map{65.+(rand(26)).chr}.join
|
46
|
-
assert dc.set("test", data)
|
47
|
-
assert_equal Dalli::GzipCompressor, dc.instance_variable_get('@ring').servers.first.compressor
|
48
|
-
assert_equal(data, dc.get("test"))
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/test/test_dalli.rb
DELETED
@@ -1,682 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'memcached_mock'
|
3
|
-
|
4
|
-
describe 'Dalli' do
|
5
|
-
describe 'options parsing' do
|
6
|
-
it 'handle deprecated options' do
|
7
|
-
dc = Dalli::Client.new('foo', :compression => true)
|
8
|
-
assert dc.instance_variable_get(:@options)[:compress]
|
9
|
-
refute dc.instance_variable_get(:@options)[:compression]
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'not warn about valid options' do
|
13
|
-
dc = Dalli::Client.new('foo', :compress => true)
|
14
|
-
# Rails.logger.expects :warn
|
15
|
-
assert dc.instance_variable_get(:@options)[:compress]
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'raises error with invalid expires_in' do
|
19
|
-
bad_data = [{:bad => 'expires in data'}, Hash, [1,2,3]]
|
20
|
-
bad_data.each do |bad|
|
21
|
-
assert_raises ArgumentError do
|
22
|
-
Dalli::Client.new('foo', {:expires_in => bad})
|
23
|
-
end
|
24
|
-
end
|
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
|
36
|
-
end
|
37
|
-
|
38
|
-
describe 'key validation' do
|
39
|
-
it 'not allow blanks' do
|
40
|
-
memcached_persistent do |dc|
|
41
|
-
dc.set ' ', 1
|
42
|
-
assert_equal 1, dc.get(' ')
|
43
|
-
dc.set "\t", 1
|
44
|
-
assert_equal 1, dc.get("\t")
|
45
|
-
dc.set "\n", 1
|
46
|
-
assert_equal 1, dc.get("\n")
|
47
|
-
assert_raises ArgumentError do
|
48
|
-
dc.set "", 1
|
49
|
-
end
|
50
|
-
assert_raises ArgumentError do
|
51
|
-
dc.set nil, 1
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'allow namespace to be a symbol' do
|
57
|
-
memcached_persistent do |dc, port|
|
58
|
-
dc = Dalli::Client.new("localhost:#{port}", :namespace => :wunderschoen)
|
59
|
-
dc.set "x" * 251, 1
|
60
|
-
assert 1, dc.get("#{'x' * 200}:md5:#{Digest::MD5.hexdigest('x' * 251)}")
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
it "default to localhost:11211" do
|
66
|
-
dc = Dalli::Client.new
|
67
|
-
ring = dc.send(:ring)
|
68
|
-
s1 = ring.servers.first.hostname
|
69
|
-
assert_equal 1, ring.servers.size
|
70
|
-
dc.close
|
71
|
-
|
72
|
-
dc = Dalli::Client.new('localhost:11211')
|
73
|
-
ring = dc.send(:ring)
|
74
|
-
s2 = ring.servers.first.hostname
|
75
|
-
assert_equal 1, ring.servers.size
|
76
|
-
dc.close
|
77
|
-
|
78
|
-
dc = Dalli::Client.new(['localhost:11211'])
|
79
|
-
ring = dc.send(:ring)
|
80
|
-
s3 = ring.servers.first.hostname
|
81
|
-
assert_equal 1, ring.servers.size
|
82
|
-
dc.close
|
83
|
-
|
84
|
-
assert_equal '127.0.0.1', s1
|
85
|
-
assert_equal s2, s3
|
86
|
-
end
|
87
|
-
|
88
|
-
it "accept comma separated string" do
|
89
|
-
dc = Dalli::Client.new("server1.example.com:11211,server2.example.com:11211")
|
90
|
-
ring = dc.send(:ring)
|
91
|
-
assert_equal 2, ring.servers.size
|
92
|
-
s1,s2 = ring.servers.map(&:hostname)
|
93
|
-
assert_equal "server1.example.com", s1
|
94
|
-
assert_equal "server2.example.com", s2
|
95
|
-
end
|
96
|
-
|
97
|
-
it "accept array of servers" do
|
98
|
-
dc = Dalli::Client.new(["server1.example.com:11211","server2.example.com:11211"])
|
99
|
-
ring = dc.send(:ring)
|
100
|
-
assert_equal 2, ring.servers.size
|
101
|
-
s1,s2 = ring.servers.map(&:hostname)
|
102
|
-
assert_equal "server1.example.com", s1
|
103
|
-
assert_equal "server2.example.com", s2
|
104
|
-
end
|
105
|
-
|
106
|
-
describe 'using a live server' do
|
107
|
-
|
108
|
-
it "support get/set" do
|
109
|
-
memcached_persistent do |dc|
|
110
|
-
dc.flush
|
111
|
-
|
112
|
-
val1 = "1234567890"*105000
|
113
|
-
assert_equal false, dc.set('a', val1)
|
114
|
-
|
115
|
-
val1 = "1234567890"*100000
|
116
|
-
dc.set('a', val1)
|
117
|
-
val2 = dc.get('a')
|
118
|
-
assert_equal val1, val2
|
119
|
-
|
120
|
-
assert op_addset_succeeds(dc.set('a', nil))
|
121
|
-
assert_nil dc.get('a')
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'supports delete' do
|
126
|
-
memcached_persistent do |dc|
|
127
|
-
dc.set('some_key', 'some_value')
|
128
|
-
assert_equal 'some_value', dc.get('some_key')
|
129
|
-
|
130
|
-
dc.delete('some_key')
|
131
|
-
assert_nil dc.get('some_key')
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'returns nil for nonexist key' do
|
136
|
-
memcached_persistent do |dc|
|
137
|
-
assert_equal nil, dc.get('notexist')
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'allows "Not found" as value' do
|
142
|
-
memcached_persistent do |dc|
|
143
|
-
dc.set('key1', 'Not found')
|
144
|
-
assert_equal 'Not found', dc.get('key1')
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
it "support stats" do
|
149
|
-
memcached_persistent do |dc|
|
150
|
-
# make sure that get_hits would not equal 0
|
151
|
-
dc.set(:a, "1234567890"*100000)
|
152
|
-
dc.get(:a)
|
153
|
-
|
154
|
-
stats = dc.stats
|
155
|
-
servers = stats.keys
|
156
|
-
assert(servers.any? do |s|
|
157
|
-
stats[s]["get_hits"].to_i != 0
|
158
|
-
end, "general stats failed")
|
159
|
-
|
160
|
-
stats_items = dc.stats(:items)
|
161
|
-
servers = stats_items.keys
|
162
|
-
assert(servers.all? do |s|
|
163
|
-
stats_items[s].keys.any? do |key|
|
164
|
-
key =~ /items:[0-9]+:number/
|
165
|
-
end
|
166
|
-
end, "stats items failed")
|
167
|
-
|
168
|
-
stats_slabs = dc.stats(:slabs)
|
169
|
-
servers = stats_slabs.keys
|
170
|
-
assert(servers.all? do |s|
|
171
|
-
stats_slabs[s].keys.any? do |key|
|
172
|
-
key == "active_slabs"
|
173
|
-
end
|
174
|
-
end, "stats slabs failed")
|
175
|
-
|
176
|
-
# reset_stats test
|
177
|
-
results = dc.reset_stats
|
178
|
-
assert(results.all? { |x| x })
|
179
|
-
stats = dc.stats
|
180
|
-
servers = stats.keys
|
181
|
-
|
182
|
-
# check if reset was performed
|
183
|
-
servers.each do |s|
|
184
|
-
assert_equal 0, dc.stats[s]["get_hits"].to_i
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
it "support the fetch operation" do
|
190
|
-
memcached_persistent do |dc|
|
191
|
-
dc.flush
|
192
|
-
|
193
|
-
expected = { 'blah' => 'blerg!' }
|
194
|
-
executed = false
|
195
|
-
value = dc.fetch('fetch_key') do
|
196
|
-
executed = true
|
197
|
-
expected
|
198
|
-
end
|
199
|
-
assert_equal expected, value
|
200
|
-
assert_equal true, executed
|
201
|
-
|
202
|
-
executed = false
|
203
|
-
value = dc.fetch('fetch_key') do
|
204
|
-
executed = true
|
205
|
-
expected
|
206
|
-
end
|
207
|
-
assert_equal expected, value
|
208
|
-
assert_equal false, executed
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
it "support the fetch operation with falsey values" do
|
213
|
-
memcached_persistent do |dc|
|
214
|
-
dc.flush
|
215
|
-
|
216
|
-
dc.set("fetch_key", false)
|
217
|
-
res = dc.fetch("fetch_key") { flunk "fetch block called" }
|
218
|
-
assert_equal false, res
|
219
|
-
|
220
|
-
dc.set("fetch_key", nil)
|
221
|
-
res = dc.fetch("fetch_key") { "bob" }
|
222
|
-
assert_equal 'bob', res
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
it "support the cas operation" do
|
227
|
-
memcached_persistent do |dc|
|
228
|
-
dc.flush
|
229
|
-
|
230
|
-
expected = { 'blah' => 'blerg!' }
|
231
|
-
|
232
|
-
resp = dc.cas('cas_key') do |value|
|
233
|
-
fail('Value it not exist')
|
234
|
-
end
|
235
|
-
assert_nil resp
|
236
|
-
|
237
|
-
mutated = { 'blah' => 'foo!' }
|
238
|
-
dc.set('cas_key', expected)
|
239
|
-
resp = dc.cas('cas_key') do |value|
|
240
|
-
assert_equal expected, value
|
241
|
-
mutated
|
242
|
-
end
|
243
|
-
assert op_cas_succeeds(resp)
|
244
|
-
|
245
|
-
resp = dc.get('cas_key')
|
246
|
-
assert_equal mutated, resp
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
it "support multi-get" do
|
251
|
-
memcached_persistent do |dc|
|
252
|
-
dc.close
|
253
|
-
dc.flush
|
254
|
-
resp = dc.get_multi(%w(a b c d e f))
|
255
|
-
assert_equal({}, resp)
|
256
|
-
|
257
|
-
dc.set('a', 'foo')
|
258
|
-
dc.set('b', 123)
|
259
|
-
dc.set('c', %w(a b c))
|
260
|
-
# Invocation without block
|
261
|
-
resp = dc.get_multi(%w(a b c d e f))
|
262
|
-
expected_resp = { 'a' => 'foo', 'b' => 123, 'c' => %w(a b c) }
|
263
|
-
assert_equal(expected_resp, resp)
|
264
|
-
|
265
|
-
# Invocation with block
|
266
|
-
dc.get_multi(%w(a b c d e f)) do |k, v|
|
267
|
-
assert(expected_resp.has_key?(k) && expected_resp[k] == v)
|
268
|
-
expected_resp.delete(k)
|
269
|
-
end
|
270
|
-
assert expected_resp.empty?
|
271
|
-
|
272
|
-
# Perform a big multi-get with 1000 elements.
|
273
|
-
arr = []
|
274
|
-
dc.multi do
|
275
|
-
1000.times do |idx|
|
276
|
-
dc.set idx, idx
|
277
|
-
arr << idx
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
result = dc.get_multi(arr)
|
282
|
-
assert_equal(1000, result.size)
|
283
|
-
assert_equal(50, result['50'])
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
it 'support raw incr/decr' do
|
288
|
-
memcached_persistent do |client|
|
289
|
-
client.flush
|
290
|
-
|
291
|
-
assert op_addset_succeeds(client.set('fakecounter', 0, 0, :raw => true))
|
292
|
-
assert_equal 1, client.incr('fakecounter', 1)
|
293
|
-
assert_equal 2, client.incr('fakecounter', 1)
|
294
|
-
assert_equal 3, client.incr('fakecounter', 1)
|
295
|
-
assert_equal 1, client.decr('fakecounter', 2)
|
296
|
-
assert_equal "1", client.get('fakecounter', :raw => true)
|
297
|
-
|
298
|
-
resp = client.incr('mycounter', 0)
|
299
|
-
assert_nil resp
|
300
|
-
|
301
|
-
resp = client.incr('mycounter', 1, 0, 2)
|
302
|
-
assert_equal 2, resp
|
303
|
-
resp = client.incr('mycounter', 1)
|
304
|
-
assert_equal 3, resp
|
305
|
-
|
306
|
-
resp = client.set('rawcounter', 10, 0, :raw => true)
|
307
|
-
assert op_cas_succeeds(resp)
|
308
|
-
|
309
|
-
resp = client.get('rawcounter', :raw => true)
|
310
|
-
assert_equal '10', resp
|
311
|
-
|
312
|
-
resp = client.incr('rawcounter', 1)
|
313
|
-
assert_equal 11, resp
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
it "support incr/decr operations" do
|
318
|
-
memcached_persistent do |dc|
|
319
|
-
dc.flush
|
320
|
-
|
321
|
-
resp = dc.decr('counter', 100, 5, 0)
|
322
|
-
assert_equal 0, resp
|
323
|
-
|
324
|
-
resp = dc.decr('counter', 10)
|
325
|
-
assert_equal 0, resp
|
326
|
-
|
327
|
-
resp = dc.incr('counter', 10)
|
328
|
-
assert_equal 10, resp
|
329
|
-
|
330
|
-
current = 10
|
331
|
-
100.times do |x|
|
332
|
-
resp = dc.incr('counter', 10)
|
333
|
-
assert_equal current + ((x+1)*10), resp
|
334
|
-
end
|
335
|
-
|
336
|
-
resp = dc.decr('10billion', 0, 5, 10)
|
337
|
-
# go over the 32-bit mark to verify proper (un)packing
|
338
|
-
resp = dc.incr('10billion', 10_000_000_000)
|
339
|
-
assert_equal 10_000_000_010, resp
|
340
|
-
|
341
|
-
resp = dc.decr('10billion', 1)
|
342
|
-
assert_equal 10_000_000_009, resp
|
343
|
-
|
344
|
-
resp = dc.decr('10billion', 0)
|
345
|
-
assert_equal 10_000_000_009, resp
|
346
|
-
|
347
|
-
resp = dc.incr('10billion', 0)
|
348
|
-
assert_equal 10_000_000_009, resp
|
349
|
-
|
350
|
-
assert_nil dc.incr('DNE', 10)
|
351
|
-
assert_nil dc.decr('DNE', 10)
|
352
|
-
|
353
|
-
resp = dc.incr('big', 100, 5, 0xFFFFFFFFFFFFFFFE)
|
354
|
-
assert_equal 0xFFFFFFFFFFFFFFFE, resp
|
355
|
-
resp = dc.incr('big', 1)
|
356
|
-
assert_equal 0xFFFFFFFFFFFFFFFF, resp
|
357
|
-
|
358
|
-
# rollover the 64-bit value, we'll get something undefined.
|
359
|
-
resp = dc.incr('big', 1)
|
360
|
-
refute_equal 0x10000000000000000, resp
|
361
|
-
dc.reset
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
it 'support the append and prepend operations' do
|
366
|
-
memcached_persistent do |dc|
|
367
|
-
dc.flush
|
368
|
-
assert op_addset_succeeds(dc.set('456', 'xyz', 0, :raw => true))
|
369
|
-
assert_equal true, dc.prepend('456', '0')
|
370
|
-
assert_equal true, dc.append('456', '9')
|
371
|
-
assert_equal '0xyz9', dc.get('456', :raw => true)
|
372
|
-
assert_equal '0xyz9', dc.get('456')
|
373
|
-
|
374
|
-
assert_equal false, dc.append('nonexist', 'abc')
|
375
|
-
assert_equal false, dc.prepend('nonexist', 'abc')
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
it 'supports replace operation' do
|
380
|
-
memcached_persistent do |dc|
|
381
|
-
dc.flush
|
382
|
-
dc.set('key', 'value')
|
383
|
-
assert op_replace_succeeds(dc.replace('key', 'value2'))
|
384
|
-
|
385
|
-
assert_equal 'value2', dc.get('key')
|
386
|
-
end
|
387
|
-
end
|
388
|
-
|
389
|
-
it 'support touch operation' do
|
390
|
-
memcached_persistent do |dc|
|
391
|
-
begin
|
392
|
-
dc.flush
|
393
|
-
dc.set 'key', 'value'
|
394
|
-
assert_equal true, dc.touch('key', 10)
|
395
|
-
assert_equal true, dc.touch('key')
|
396
|
-
assert_equal 'value', dc.get('key')
|
397
|
-
assert_nil dc.touch('notexist')
|
398
|
-
rescue Dalli::DalliError => e
|
399
|
-
# This will happen when memcached is in lesser version than 1.4.8
|
400
|
-
assert_equal 'Response error 129: Unknown command', e.message
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
it 'support version operation' do
|
406
|
-
memcached_persistent do |dc|
|
407
|
-
v = dc.version
|
408
|
-
servers = v.keys
|
409
|
-
assert(servers.any? do |s|
|
410
|
-
v[s] != nil
|
411
|
-
end, "version failed")
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
it 'allow TCP connections to be configured for keepalive' do
|
416
|
-
memcached_persistent do |dc, port|
|
417
|
-
dc = Dalli::Client.new("localhost:#{port}", :keepalive => true)
|
418
|
-
dc.set(:a, 1)
|
419
|
-
ring = dc.send(:ring)
|
420
|
-
server = ring.servers.first
|
421
|
-
socket = server.instance_variable_get('@sock')
|
422
|
-
|
423
|
-
optval = socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE)
|
424
|
-
optval = optval.unpack 'i'
|
425
|
-
|
426
|
-
assert_equal true, (optval[0] != 0)
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
it "pass a simple smoke test" do
|
431
|
-
memcached_persistent do |dc, port|
|
432
|
-
resp = dc.flush
|
433
|
-
refute_nil resp
|
434
|
-
assert_equal [true, true], resp
|
435
|
-
|
436
|
-
assert op_addset_succeeds(dc.set(:foo, 'bar'))
|
437
|
-
assert_equal 'bar', dc.get(:foo)
|
438
|
-
|
439
|
-
resp = dc.get('123')
|
440
|
-
assert_equal nil, resp
|
441
|
-
|
442
|
-
assert op_addset_succeeds(dc.set('123', 'xyz'))
|
443
|
-
|
444
|
-
resp = dc.get('123')
|
445
|
-
assert_equal 'xyz', resp
|
446
|
-
|
447
|
-
assert op_addset_succeeds(dc.set('123', 'abc'))
|
448
|
-
|
449
|
-
dc.prepend('123', '0')
|
450
|
-
dc.append('123', '0')
|
451
|
-
|
452
|
-
assert_raises Dalli::UnmarshalError do
|
453
|
-
resp = dc.get('123')
|
454
|
-
end
|
455
|
-
|
456
|
-
dc.close
|
457
|
-
dc = nil
|
458
|
-
|
459
|
-
dc = Dalli::Client.new("localhost:#{port}")
|
460
|
-
|
461
|
-
assert op_addset_succeeds(dc.set('456', 'xyz', 0, :raw => true))
|
462
|
-
|
463
|
-
resp = dc.prepend '456', '0'
|
464
|
-
assert_equal true, resp
|
465
|
-
|
466
|
-
resp = dc.append '456', '9'
|
467
|
-
assert_equal true, resp
|
468
|
-
|
469
|
-
resp = dc.get('456', :raw => true)
|
470
|
-
assert_equal '0xyz9', resp
|
471
|
-
|
472
|
-
assert op_addset_succeeds(dc.set('456', false))
|
473
|
-
|
474
|
-
resp = dc.get('456')
|
475
|
-
assert_equal false, resp
|
476
|
-
|
477
|
-
resp = dc.stats
|
478
|
-
assert_equal Hash, resp.class
|
479
|
-
|
480
|
-
dc.close
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
it "pass a simple smoke test on unix socket" do
|
485
|
-
memcached_persistent(MemcachedMock::UNIX_SOCKET_PATH) do |dc, path|
|
486
|
-
resp = dc.flush
|
487
|
-
refute_nil resp
|
488
|
-
assert_equal [true], resp
|
489
|
-
|
490
|
-
assert op_addset_succeeds(dc.set(:foo, 'bar'))
|
491
|
-
assert_equal 'bar', dc.get(:foo)
|
492
|
-
|
493
|
-
resp = dc.get('123')
|
494
|
-
assert_equal nil, resp
|
495
|
-
|
496
|
-
assert op_addset_succeeds(dc.set('123', 'xyz'))
|
497
|
-
|
498
|
-
resp = dc.get('123')
|
499
|
-
assert_equal 'xyz', resp
|
500
|
-
|
501
|
-
assert op_addset_succeeds(dc.set('123', 'abc'))
|
502
|
-
|
503
|
-
dc.prepend('123', '0')
|
504
|
-
dc.append('123', '0')
|
505
|
-
|
506
|
-
assert_raises Dalli::UnmarshalError do
|
507
|
-
resp = dc.get('123')
|
508
|
-
end
|
509
|
-
|
510
|
-
dc.close
|
511
|
-
dc = nil
|
512
|
-
|
513
|
-
dc = Dalli::Client.new(path)
|
514
|
-
|
515
|
-
assert op_addset_succeeds(dc.set('456', 'xyz', 0, :raw => true))
|
516
|
-
|
517
|
-
resp = dc.prepend '456', '0'
|
518
|
-
assert_equal true, resp
|
519
|
-
|
520
|
-
resp = dc.append '456', '9'
|
521
|
-
assert_equal true, resp
|
522
|
-
|
523
|
-
resp = dc.get('456', :raw => true)
|
524
|
-
assert_equal '0xyz9', resp
|
525
|
-
|
526
|
-
assert op_addset_succeeds(dc.set('456', false))
|
527
|
-
|
528
|
-
resp = dc.get('456')
|
529
|
-
assert_equal false, resp
|
530
|
-
|
531
|
-
resp = dc.stats
|
532
|
-
assert_equal Hash, resp.class
|
533
|
-
|
534
|
-
dc.close
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
it "support multithreaded access" do
|
539
|
-
memcached_persistent do |cache|
|
540
|
-
cache.flush
|
541
|
-
workers = []
|
542
|
-
|
543
|
-
cache.set('f', 'zzz')
|
544
|
-
assert op_cas_succeeds((cache.cas('f') do |value|
|
545
|
-
value << 'z'
|
546
|
-
end))
|
547
|
-
assert_equal 'zzzz', cache.get('f')
|
548
|
-
|
549
|
-
# Have a bunch of threads perform a bunch of operations at the same time.
|
550
|
-
# Verify the result of each operation to ensure the request and response
|
551
|
-
# are not intermingled between threads.
|
552
|
-
10.times do
|
553
|
-
workers << Thread.new do
|
554
|
-
100.times do
|
555
|
-
cache.set('a', 9)
|
556
|
-
cache.set('b', 11)
|
557
|
-
inc = cache.incr('cat', 10, 0, 10)
|
558
|
-
cache.set('f', 'zzz')
|
559
|
-
res = cache.cas('f') do |value|
|
560
|
-
value << 'z'
|
561
|
-
end
|
562
|
-
refute_nil res
|
563
|
-
assert_equal false, cache.add('a', 11)
|
564
|
-
assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
|
565
|
-
inc = cache.incr('cat', 10)
|
566
|
-
assert_equal 0, inc % 5
|
567
|
-
cache.decr('cat', 5)
|
568
|
-
assert_equal 11, cache.get('b')
|
569
|
-
|
570
|
-
assert_equal %w(a b), cache.get_multi('a', 'b', 'c').keys.sort
|
571
|
-
|
572
|
-
end
|
573
|
-
end
|
574
|
-
end
|
575
|
-
|
576
|
-
workers.each { |w| w.join }
|
577
|
-
cache.flush
|
578
|
-
end
|
579
|
-
end
|
580
|
-
|
581
|
-
it "handle namespaced keys" do
|
582
|
-
memcached_persistent do |dc, port|
|
583
|
-
dc = Dalli::Client.new("localhost:#{port}", :namespace => 'a')
|
584
|
-
dc.set('namespaced', 1)
|
585
|
-
dc2 = Dalli::Client.new("localhost:#{port}", :namespace => 'b')
|
586
|
-
dc2.set('namespaced', 2)
|
587
|
-
assert_equal 1, dc.get('namespaced')
|
588
|
-
assert_equal 2, dc2.get('namespaced')
|
589
|
-
end
|
590
|
-
end
|
591
|
-
|
592
|
-
it "handle nil namespace" do
|
593
|
-
memcached_persistent do |dc, port|
|
594
|
-
dc = Dalli::Client.new("localhost:#{port}", :namespace => nil)
|
595
|
-
assert_equal 'key', dc.send(:validate_key, 'key')
|
596
|
-
end
|
597
|
-
end
|
598
|
-
|
599
|
-
it 'truncate cache keys that are too long' do
|
600
|
-
memcached_persistent do |dc, port|
|
601
|
-
dc = Dalli::Client.new("localhost:#{port}", :namespace => 'some:namspace')
|
602
|
-
key = "this cache key is far too long so it must be hashed and truncated and stuff" * 10
|
603
|
-
value = "some value"
|
604
|
-
assert op_addset_succeeds(dc.set(key, value))
|
605
|
-
assert_equal value, dc.get(key)
|
606
|
-
end
|
607
|
-
end
|
608
|
-
|
609
|
-
it "handle namespaced keys in multi_get" do
|
610
|
-
memcached_persistent do |dc, port|
|
611
|
-
dc = Dalli::Client.new("localhost:#{port}", :namespace => 'a')
|
612
|
-
dc.set('a', 1)
|
613
|
-
dc.set('b', 2)
|
614
|
-
assert_equal({'a' => 1, 'b' => 2}, dc.get_multi('a', 'b'))
|
615
|
-
end
|
616
|
-
end
|
617
|
-
|
618
|
-
it "handle application marshalling issues" do
|
619
|
-
memcached_persistent do |dc|
|
620
|
-
old = Dalli.logger
|
621
|
-
Dalli.logger = Logger.new(nil)
|
622
|
-
begin
|
623
|
-
assert_equal false, dc.set('a', Proc.new { true })
|
624
|
-
ensure
|
625
|
-
Dalli.logger = old
|
626
|
-
end
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
describe 'with compression' do
|
631
|
-
it 'allow large values' do
|
632
|
-
memcached_persistent do |dc|
|
633
|
-
dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :compress => true)
|
634
|
-
|
635
|
-
value = "0"*1024*1024
|
636
|
-
assert_equal false, dc.set('verylarge', value)
|
637
|
-
dalli.set('verylarge', value)
|
638
|
-
end
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
describe 'in low memory conditions' do
|
643
|
-
|
644
|
-
it 'handle error response correctly' do
|
645
|
-
memcached_low_mem_persistent do |dc|
|
646
|
-
failed = false
|
647
|
-
value = "1234567890"*100
|
648
|
-
1_000.times do |idx|
|
649
|
-
begin
|
650
|
-
assert op_addset_succeeds(dc.set(idx, value))
|
651
|
-
rescue Dalli::DalliError
|
652
|
-
failed = true
|
653
|
-
assert((800..960).include?(idx), "unexpected failure on iteration #{idx}")
|
654
|
-
break
|
655
|
-
end
|
656
|
-
end
|
657
|
-
assert failed, 'did not fail under low memory conditions'
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
it 'fit more values with compression' do
|
662
|
-
memcached_low_mem_persistent do |dc, port|
|
663
|
-
dalli = Dalli::Client.new("localhost:#{port}", :compress => true)
|
664
|
-
failed = false
|
665
|
-
value = "1234567890"*1000
|
666
|
-
10_000.times do |idx|
|
667
|
-
begin
|
668
|
-
assert op_addset_succeeds(dalli.set(idx, value))
|
669
|
-
rescue Dalli::DalliError
|
670
|
-
failed = true
|
671
|
-
assert((6000..7800).include?(idx), "unexpected failure on iteration #{idx}")
|
672
|
-
break
|
673
|
-
end
|
674
|
-
end
|
675
|
-
assert failed, 'did not fail under low memory conditions'
|
676
|
-
end
|
677
|
-
end
|
678
|
-
|
679
|
-
end
|
680
|
-
|
681
|
-
end
|
682
|
-
end
|