sayso-dalli 1.0.3.001

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,213 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+
4
+ class TestActiveSupport < Test::Unit::TestCase
5
+ context 'active_support caching' do
6
+
7
+ should 'support fetch' do
8
+ with_activesupport do
9
+ memcached do
10
+ connect
11
+ mvalue = @mc.fetch('somekeywithoutspaces', :expires_in => 1.second) { 123 }
12
+ dvalue = @dalli.fetch('someotherkeywithoutspaces', :expires_in => 1.second) { 123 }
13
+ assert_equal 123, dvalue
14
+ assert_equal mvalue, dvalue
15
+
16
+ o = Object.new
17
+ o.instance_variable_set :@foo, 'bar'
18
+ mvalue = @mc.fetch(rand_key, :raw => true) { o }
19
+ dvalue = @dalli.fetch(rand_key, :raw => true) { o }
20
+ assert_equal mvalue, dvalue
21
+ assert_equal o, mvalue
22
+
23
+ mvalue = @mc.fetch(rand_key) { o }
24
+ dvalue = @dalli.fetch(rand_key) { o }
25
+ assert_equal mvalue, dvalue
26
+ assert_equal o, dvalue
27
+ end
28
+ end
29
+ end
30
+
31
+ should 'support keys with spaces on Rails3' do
32
+ with_activesupport do
33
+ memcached do
34
+ connect
35
+ case
36
+ when rails3?
37
+ dvalue = @mc.fetch('some key with spaces', :expires_in => 1.second) { 123 }
38
+ mvalue = @dalli.fetch('some other key with spaces', :expires_in => 1.second) { 123 }
39
+ assert_equal mvalue, dvalue
40
+ else
41
+ assert_raises ArgumentError do
42
+ @mc.fetch('some key with spaces', :expires_in => 1.second) { 123 }
43
+ end
44
+ assert_raises ArgumentError do
45
+ @dalli.fetch('some other key with spaces', :expires_in => 1.second) { 123 }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ should 'support read_multi' do
53
+ with_activesupport do
54
+ memcached do
55
+ connect
56
+ x = rand_key
57
+ y = rand_key
58
+ assert_equal({}, @mc.read_multi(x, y))
59
+ assert_equal({}, @dalli.read_multi(x, y))
60
+ @dalli.write(x, '123')
61
+ @dalli.write(y, 123)
62
+ @mc.write(x, '123')
63
+ @mc.write(y, 123)
64
+ assert_equal({ x => '123', y => 123 }, @dalli.read_multi(x, y))
65
+ assert_equal({ x => '123', y => 123 }, @mc.read_multi(x, y))
66
+ end
67
+ end
68
+ end
69
+
70
+ should 'support read_multi with an array' do
71
+ with_activesupport do
72
+ memcached do
73
+ connect
74
+ case
75
+ when rails3?
76
+ x = rand_key
77
+ y = rand_key
78
+ assert_equal({}, @mc.read_multi([x, y]))
79
+ assert_equal({}, @dalli.read_multi([x, y]))
80
+ @dalli.write(x, '123')
81
+ @dalli.write(y, 123)
82
+ @mc.write(x, '123')
83
+ @mc.write(y, 123)
84
+ assert_equal({ x => '123', y => 123 }, @dalli.read_multi([x, y]))
85
+ assert_equal({}, @mc.read_multi([x,y]))
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ should 'support raw read_multi' do
92
+ with_activesupport do
93
+ memcached do
94
+ connect
95
+ @mc.write("abc", 5, :raw => true)
96
+ @mc.write("cba", 5, :raw => true)
97
+ if RAILS_VERSION =~ /2\.3/
98
+ assert_raise ArgumentError do
99
+ @mc.read_multi("abc", "cba")
100
+ end
101
+ else
102
+ assert_equal({'abc' => '5', 'cba' => '5' }, @mc.read_multi("abc", "cba"))
103
+ end
104
+
105
+ @dalli.write("abc", 5, :raw => true)
106
+ @dalli.write("cba", 5, :raw => true)
107
+ # XXX: API difference between m-c and dalli. Dalli is smarter about
108
+ # what it needs to unmarshal.
109
+ assert_equal({'abc' => '5', 'cba' => '5' }, @dalli.read_multi("abc", "cba"))
110
+ end
111
+ end
112
+ end
113
+
114
+ should 'support read, write and delete' do
115
+ with_activesupport do
116
+ memcached do
117
+ connect
118
+ x = rand_key
119
+ y = rand_key
120
+ assert_nil @mc.read(x)
121
+ assert_nil @dalli.read(y)
122
+ mres = @mc.write(x, 123)
123
+ dres = @dalli.write(y, 123)
124
+ assert_equal mres, dres
125
+
126
+ mres = @mc.read(x)
127
+ dres = @dalli.read(y)
128
+ assert_equal mres, dres
129
+ assert_equal 123, dres
130
+
131
+ mres = @mc.delete(x)
132
+ dres = @dalli.delete(y)
133
+ assert_equal mres, dres
134
+ assert_equal true, dres
135
+ end
136
+ end
137
+ end
138
+
139
+ should 'support increment/decrement commands' do
140
+ with_activesupport do
141
+ memcached do
142
+ connect
143
+ assert_equal true, @mc.write('counter', 0, :raw => true)
144
+ assert_equal 1, @mc.increment('counter')
145
+ assert_equal 2, @mc.increment('counter')
146
+ assert_equal 1, @mc.decrement('counter')
147
+ assert_equal "1", @mc.read('counter', :raw => true)
148
+
149
+ assert_equal true, @dalli.write('counter', 0, :raw => true)
150
+ assert_equal 1, @dalli.increment('counter')
151
+ assert_equal 2, @dalli.increment('counter')
152
+ assert_equal 1, @dalli.decrement('counter')
153
+ assert_equal "1", @dalli.read('counter', :raw => true)
154
+
155
+ assert_equal 0, @mc.increment('counterX')
156
+ assert_equal 0, @mc.increment('counterX')
157
+ assert_equal nil, @mc.read('counterX')
158
+
159
+ assert_equal 1, @dalli.increment('counterX')
160
+ assert_equal 2, @dalli.increment('counterX')
161
+ assert_equal 2, @dalli.read('counterX', :raw => true).to_i
162
+ end
163
+ end
164
+ end
165
+
166
+ should 'support other esoteric commands' do
167
+ with_activesupport do
168
+ memcached do
169
+ connect
170
+ ms = @mc.stats
171
+ ds = @dalli.stats
172
+ assert_equal ms.keys.sort, ds.keys.sort
173
+ assert_equal ms[ms.keys.first].keys.sort, ds[ds.keys.first].keys.sort
174
+
175
+ assert_equal true, @dalli.write(:foo, 'a')
176
+ assert_equal true, @mc.write(:foo, 'a')
177
+
178
+ assert_equal true, @mc.exist?(:foo)
179
+ assert_equal true, @dalli.exist?(:foo)
180
+
181
+ assert_equal false, @mc.exist?(:bar)
182
+ assert_equal false, @dalli.exist?(:bar)
183
+
184
+ @dalli.reset
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ should 'handle crazy characters from far-away lands' do
191
+ with_activesupport do
192
+ memcached do
193
+ connect
194
+ key = "fooƒ"
195
+ value = 'bafƒ'
196
+ # assert_equal true, @mc.write(key, value)
197
+ assert_equal true, @dalli.write(key, value)
198
+ # assert_equal true, @mc.read(key, value)
199
+ assert_equal value, @dalli.read(key)
200
+ end
201
+ end
202
+ end
203
+
204
+ def connect
205
+ @dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'x')
206
+ @mc = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'a')
207
+ @dalli.clear
208
+ end
209
+
210
+ def rand_key
211
+ rand(1_000_000_000)
212
+ end
213
+ end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class TestCompatibility < Test::Unit::TestCase
4
+
5
+ def setup
6
+ require 'dalli/memcache-client'
7
+ end
8
+
9
+ context 'dalli in memcache-client mode' do
10
+
11
+ should 'handle old raw flag to set/add/replace' do
12
+ memcached do |dc|
13
+ assert_equal "STORED\r\n", dc.set('abc', 123, 5, true)
14
+ assert_equal '123', dc.get('abc', true)
15
+
16
+ assert_equal "NOT_STORED\r\n", dc.add('abc', 456, 5, true)
17
+ assert_equal '123', dc.get('abc', true)
18
+
19
+ assert_equal "STORED\r\n", dc.replace('abc', 456, 5, false)
20
+ assert_equal 456, dc.get('abc', false)
21
+
22
+ assert_equal "DELETED\r\n", dc.delete('abc')
23
+ assert_equal "NOT_DELETED\r\n", dc.delete('abc')
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ def teardown
30
+ Dalli::Client.compatibility_mode = false
31
+ end
32
+
33
+ end
@@ -0,0 +1,398 @@
1
+ require 'helper'
2
+ require 'memcached_mock'
3
+
4
+ class TestDalli < Test::Unit::TestCase
5
+
6
+ should "default to localhost:11211" do
7
+ dc = Dalli::Client.new
8
+ ring = dc.send(:ring)
9
+ s1 = ring.servers.first.hostname
10
+ assert_equal 1, ring.servers.size
11
+ dc.close
12
+
13
+ dc = Dalli::Client.new('localhost:11211')
14
+ ring = dc.send(:ring)
15
+ s2 = ring.servers.first.hostname
16
+ assert_equal 1, ring.servers.size
17
+ dc.close
18
+
19
+ dc = Dalli::Client.new(['localhost:11211'])
20
+ ring = dc.send(:ring)
21
+ s3 = ring.servers.first.hostname
22
+ assert_equal 1, ring.servers.size
23
+ dc.close
24
+
25
+ assert_equal s1, s2
26
+ assert_equal s2, s3
27
+ end
28
+
29
+ context 'using a live server' do
30
+
31
+ should "support get/set" do
32
+ memcached do |dc|
33
+ dc.flush
34
+
35
+ val1 = "1234567890"*105000
36
+ assert_error Dalli::DalliError, /too large/ do
37
+ dc.set('a', val1)
38
+ val2 = dc.get('a')
39
+ assert_equal val1, val2
40
+ end
41
+
42
+ val1 = "1234567890"*100000
43
+ dc.set('a', val1)
44
+ val2 = dc.get('a')
45
+ assert_equal val1, val2
46
+
47
+ assert_equal true, dc.set('a', nil)
48
+ assert_nil dc.get('a')
49
+ end
50
+ end
51
+
52
+ should "support the fetch operation" do
53
+ memcached do |dc|
54
+ dc.flush
55
+
56
+ expected = { 'blah' => 'blerg!' }
57
+ executed = false
58
+ value = dc.fetch('fetch_key') do
59
+ executed = true
60
+ expected
61
+ end
62
+ assert_equal expected, value
63
+ assert_equal true, executed
64
+
65
+ executed = false
66
+ value = dc.fetch('fetch_key') do
67
+ executed = true
68
+ expected
69
+ end
70
+ assert_equal expected, value
71
+ assert_equal false, executed
72
+ end
73
+ end
74
+
75
+ should "support the cas operation" do
76
+ memcached do |dc|
77
+ dc.flush
78
+
79
+ expected = { 'blah' => 'blerg!' }
80
+
81
+ resp = dc.cas('cas_key') do |value|
82
+ fail('Value should not exist')
83
+ end
84
+ assert_nil resp
85
+
86
+ mutated = { 'blah' => 'foo!' }
87
+ dc.set('cas_key', expected)
88
+ resp = dc.cas('cas_key') do |value|
89
+ assert_equal expected, value
90
+ mutated
91
+ end
92
+ assert_equal true, resp
93
+
94
+ resp = dc.get('cas_key')
95
+ assert_equal mutated, resp
96
+
97
+ # TODO Need to verify failure when value is mutated between get and add.
98
+ end
99
+ end
100
+
101
+ should "support multi-get" do
102
+ memcached do |dc|
103
+ dc.close
104
+ dc.flush
105
+ resp = dc.get_multi(%w(a b c d e f))
106
+ assert_equal({}, resp)
107
+
108
+ dc.set('a', 'foo')
109
+ dc.set('b', 123)
110
+ dc.set('c', %w(a b c))
111
+ resp = dc.get_multi(%w(a b c d e f))
112
+ assert_equal({ 'a' => 'foo', 'b' => 123, 'c' => %w(a b c) }, resp)
113
+
114
+ # Perform a huge multi-get with 10,000 elements.
115
+ arr = []
116
+ dc.multi do
117
+ 10_000.times do |idx|
118
+ dc.set idx, idx
119
+ arr << idx
120
+ end
121
+ end
122
+
123
+ result = dc.get_multi(arr)
124
+ assert_equal(10_000, result.size)
125
+ assert_equal(1000, result['1000'])
126
+ end
127
+ end
128
+
129
+ should 'support raw incr/decr' do
130
+ memcached do |client|
131
+ client.flush
132
+
133
+ assert_equal true, client.set('fakecounter', 0, 0, :raw => true)
134
+ assert_equal 1, client.incr('fakecounter', 1)
135
+ assert_equal 2, client.incr('fakecounter', 1)
136
+ assert_equal 3, client.incr('fakecounter', 1)
137
+ assert_equal 1, client.decr('fakecounter', 2)
138
+ assert_equal "1", client.get('fakecounter', :raw => true)
139
+
140
+ resp = client.incr('mycounter', 0)
141
+ assert_nil resp
142
+
143
+ resp = client.incr('mycounter', 1, 0, 2)
144
+ assert_equal 2, resp
145
+ resp = client.incr('mycounter', 1)
146
+ assert_equal 3, resp
147
+
148
+ resp = client.set('rawcounter', 10, 0, :raw => true)
149
+ assert_equal true, resp
150
+
151
+ resp = client.get('rawcounter', :raw => true)
152
+ assert_equal '10', resp
153
+
154
+ resp = client.incr('rawcounter', 1)
155
+ assert_equal 11, resp
156
+ end
157
+ end
158
+
159
+ should "support incr/decr operations" do
160
+ memcached do |dc|
161
+ dc.flush
162
+
163
+ resp = dc.decr('counter', 100, 5, 0)
164
+ assert_equal 0, resp
165
+
166
+ resp = dc.decr('counter', 10)
167
+ assert_equal 0, resp
168
+
169
+ resp = dc.incr('counter', 10)
170
+ assert_equal 10, resp
171
+
172
+ current = 10
173
+ 100.times do |x|
174
+ resp = dc.incr('counter', 10)
175
+ assert_equal current + ((x+1)*10), resp
176
+ end
177
+
178
+ resp = dc.decr('10billion', 0, 5, 10)
179
+ # go over the 32-bit mark to verify proper (un)packing
180
+ resp = dc.incr('10billion', 10_000_000_000)
181
+ assert_equal 10_000_000_010, resp
182
+
183
+ resp = dc.decr('10billion', 1)
184
+ assert_equal 10_000_000_009, resp
185
+
186
+ resp = dc.decr('10billion', 0)
187
+ assert_equal 10_000_000_009, resp
188
+
189
+ resp = dc.incr('10billion', 0)
190
+ assert_equal 10_000_000_009, resp
191
+
192
+ assert_nil dc.incr('DNE', 10)
193
+ assert_nil dc.decr('DNE', 10)
194
+
195
+ resp = dc.incr('big', 100, 5, 0xFFFFFFFFFFFFFFFE)
196
+ assert_equal 0xFFFFFFFFFFFFFFFE, resp
197
+ resp = dc.incr('big', 1)
198
+ assert_equal 0xFFFFFFFFFFFFFFFF, resp
199
+
200
+ # rollover the 64-bit value, we'll get something undefined.
201
+ resp = dc.incr('big', 1)
202
+ assert_not_equal 0x10000000000000000, resp
203
+ dc.reset
204
+ end
205
+ end
206
+
207
+ should 'support the append and prepend operations' do
208
+ memcached do |dc|
209
+ resp = dc.flush
210
+ assert_equal true, dc.set('456', 'xyz', 0, :raw => true)
211
+ assert_equal true, dc.prepend('456', '0')
212
+ assert_equal true, dc.append('456', '9')
213
+ assert_equal '0xyz9', dc.get('456', :raw => true)
214
+ assert_equal '0xyz9', dc.get('456')
215
+
216
+ assert_equal false, dc.append('nonexist', 'abc')
217
+ assert_equal false, dc.prepend('nonexist', 'abc')
218
+ end
219
+ end
220
+
221
+ should "pass a simple smoke test" do
222
+ memcached do |dc|
223
+ resp = dc.flush
224
+ assert_not_nil resp
225
+ assert_equal [true, true], resp
226
+
227
+ assert_equal true, dc.set(:foo, 'bar')
228
+ assert_equal 'bar', dc.get(:foo)
229
+
230
+ resp = dc.get('123')
231
+ assert_equal nil, resp
232
+
233
+ resp = dc.set('123', 'xyz')
234
+ assert_equal true, resp
235
+
236
+ resp = dc.get('123')
237
+ assert_equal 'xyz', resp
238
+
239
+ resp = dc.set('123', 'abc')
240
+ assert_equal true, resp
241
+
242
+ dc.prepend('123', '0')
243
+ dc.append('123', '0')
244
+
245
+ assert_raises Dalli::DalliError do
246
+ resp = dc.get('123')
247
+ end
248
+
249
+ dc.close
250
+ dc = nil
251
+
252
+ dc = Dalli::Client.new('localhost:19122')
253
+
254
+ resp = dc.set('456', 'xyz', 0, :raw => true)
255
+ assert_equal true, resp
256
+
257
+ resp = dc.prepend '456', '0'
258
+ assert_equal true, resp
259
+
260
+ resp = dc.append '456', '9'
261
+ assert_equal true, resp
262
+
263
+ resp = dc.get('456', :raw => true)
264
+ assert_equal '0xyz9', resp
265
+
266
+ resp = dc.stats
267
+ assert_equal Hash, resp.class
268
+
269
+ dc.close
270
+ end
271
+ end
272
+
273
+ should "support multithreaded access" do
274
+ memcached do |cache|
275
+ cache.flush
276
+ workers = []
277
+
278
+ cache.set('f', 'zzz')
279
+ assert_equal true, (cache.cas('f') do |value|
280
+ value << 'z'
281
+ end)
282
+ assert_equal 'zzzz', cache.get('f')
283
+
284
+ # Have a bunch of threads perform a bunch of operations at the same time.
285
+ # Verify the result of each operation to ensure the request and response
286
+ # are not intermingled between threads.
287
+ 10.times do
288
+ workers << Thread.new do
289
+ 100.times do
290
+ cache.set('a', 9)
291
+ cache.set('b', 11)
292
+ inc = cache.incr('cat', 10, 0, 10)
293
+ cache.set('f', 'zzz')
294
+ assert_not_nil(cache.cas('f') do |value|
295
+ value << 'z'
296
+ end)
297
+ assert_equal false, cache.add('a', 11)
298
+ assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
299
+ inc = cache.incr('cat', 10)
300
+ assert_equal 0, inc % 5
301
+ dec = cache.decr('cat', 5)
302
+ assert_equal 11, cache.get('b')
303
+ end
304
+ end
305
+ end
306
+
307
+ workers.each { |w| w.join }
308
+ cache.flush
309
+ end
310
+ end
311
+
312
+ should "handle namespaced keys" do
313
+ memcached do |dc|
314
+ dc = Dalli::Client.new('localhost:19122', :namespace => 'a')
315
+ dc.set('namespaced', 1)
316
+ dc2 = Dalli::Client.new('localhost:19122', :namespace => 'b')
317
+ dc2.set('namespaced', 2)
318
+ assert_equal 1, dc.get('namespaced')
319
+ assert_equal 2, dc2.get('namespaced')
320
+ end
321
+ end
322
+
323
+ should "handle namespaced keys in multi_get" do
324
+ memcached do |dc|
325
+ dc = Dalli::Client.new('localhost:19122', :namespace => 'a')
326
+ dc.set('a', 1)
327
+ dc.set('b', 2)
328
+ assert_equal({'a' => 1, 'b' => 2}, dc.get_multi('a', 'b'))
329
+ end
330
+ end
331
+
332
+ should "handle application marshalling issues" do
333
+ memcached do |dc|
334
+ old = Dalli.logger
335
+ Dalli.logger = Logger.new(nil)
336
+ begin
337
+ assert_equal false, dc.set('a', Proc.new { true })
338
+ ensure
339
+ Dalli.logger = old
340
+ end
341
+ end
342
+ end
343
+
344
+ context 'with compression' do
345
+ should 'allow large values' do
346
+ memcached do |dc|
347
+ dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :compression => true)
348
+
349
+ value = "0"*1024*1024
350
+ assert_raise Dalli::DalliError, /too large/ do
351
+ dc.set('verylarge', value)
352
+ end
353
+ dalli.set('verylarge', value)
354
+ end
355
+ end
356
+ end
357
+
358
+ context 'in low memory conditions' do
359
+
360
+ should 'handle error response correctly' do
361
+ memcached(19125, '-m 1 -M') do |dc|
362
+ failed = false
363
+ value = "1234567890"*100
364
+ 1_000.times do |idx|
365
+ begin
366
+ assert_equal true, dc.set(idx, value)
367
+ rescue Dalli::DalliError
368
+ failed = true
369
+ assert((800..900).include?(idx), "unexpected failure on iteration #{idx}")
370
+ break
371
+ end
372
+ end
373
+ assert failed, 'did not fail under low memory conditions'
374
+ end
375
+ end
376
+
377
+ should 'fit more values with compression' do
378
+ memcached(19126, '-m 1 -M') do |dc|
379
+ dalli = Dalli::Client.new('localhost:19126', :compression => true)
380
+ failed = false
381
+ value = "1234567890"*1000
382
+ 10_000.times do |idx|
383
+ begin
384
+ assert_equal true, dalli.set(idx, value)
385
+ rescue Dalli::DalliError
386
+ failed = true
387
+ assert((6000..7000).include?(idx), "unexpected failure on iteration #{idx}")
388
+ break
389
+ end
390
+ end
391
+ assert failed, 'did not fail under low memory conditions'
392
+ end
393
+ end
394
+
395
+ end
396
+
397
+ end
398
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+ require 'memcached_mock'
4
+
5
+ class TestEncoding < Test::Unit::TestCase
6
+
7
+ context 'using a live server' do
8
+ should 'support i18n content' do
9
+ memcached do |dc|
10
+ key = 'foo'
11
+ bad_key = utf8 = 'ƒ©åÍÎ'
12
+
13
+ assert dc.set(key, utf8)
14
+ assert_equal utf8, dc.get(key)
15
+
16
+ # keys must be ASCII
17
+ assert_raise ArgumentError, /illegal character/ do
18
+ dc.set(bad_key, utf8)
19
+ end
20
+ end
21
+ end
22
+
23
+ should 'support content expiry' do
24
+ memcached do |dc|
25
+ key = 'foo'
26
+ assert dc.set(key, 'bar', 1)
27
+ assert_equal 'bar', dc.get(key)
28
+ sleep 2
29
+ assert_equal nil, dc.get(key)
30
+ end
31
+ end
32
+
33
+ should 'not allow non-ASCII keys' do
34
+ memcached do |dc|
35
+ key = 'fooƒ'
36
+ assert_raise ArgumentError do
37
+ dc.set(key, 'bar')
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+ end