jjp-memcache-client 1.8.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,110 @@
1
+ # encoding: ascii-8bit
2
+ require 'test/unit'
3
+ require 'memcache'
4
+
5
+ class TestEventMachine < Test::Unit::TestCase
6
+
7
+ def test_concurrent_fibers
8
+ return puts("Skipping EventMachine test, not Ruby 1.9") if RUBY_VERSION < '1.9'
9
+ return puts("Skipping EventMachine test, no live server") if !live_server?
10
+
11
+ require 'eventmachine'
12
+ require 'memcache/event_machine'
13
+ ex = nil
14
+ m = MemCache.new(['127.0.0.1:11211', 'localhost:11211'])
15
+ within_em(3) do
16
+ begin
17
+ key1 = 'foo'
18
+ key2 = 'bar'*50
19
+ key3 = '£∞'*45
20
+ value1 = 'abc'
21
+ value2 = 'xyz'*1000
22
+ value3 = '∞§¶•ª'*1000
23
+
24
+ 100.times do
25
+ assert_equal "STORED\r\n", m.set(key1, value1)
26
+ assert_equal "STORED\r\n", m.set(key2, value2)
27
+ assert_equal "STORED\r\n", m.set(key3, value3)
28
+ m.get(key1)
29
+ m.get(key2)
30
+ m.get(key3)
31
+ assert m.delete(key1)
32
+ assert_equal "STORED\r\n", m.set(key1, value2)
33
+ m.get(key1)
34
+ assert_equal "STORED\r\n", m.set(key2, value3)
35
+ m.get(key2)
36
+ assert_equal "STORED\r\n", m.set(key3, value1)
37
+ m.get(key3)
38
+ h = m.get_multi(key1, key2, key3)
39
+ assert h
40
+ assert_equal Hash, h.class
41
+ assert h.size > 0
42
+ end
43
+ rescue Exception => exp
44
+ puts exp.message
45
+ ex = exp
46
+ ensure
47
+ EM.stop
48
+ end
49
+ end
50
+ raise ex if ex
51
+ end
52
+
53
+ def test_live_server
54
+ return puts("Skipping EventMachine test, not Ruby 1.9") if RUBY_VERSION < '1.9'
55
+ return puts("Skipping EventMachine test, no live server") if !live_server?
56
+
57
+ require 'eventmachine'
58
+ require 'memcache/event_machine'
59
+ ex = nil
60
+ within_em do
61
+ begin
62
+ m = MemCache.new(['127.0.0.1:11211', 'localhost:11211'])
63
+ key1 = 'foo'
64
+ key2 = 'bar'*50
65
+ key3 = '£∞'*50
66
+ value1 = 'abc'
67
+ value2 = 'xyz'*1000
68
+ value3 = '∞§¶•ª'*1000
69
+
70
+ 1000.times do
71
+ assert_equal "STORED\r\n", m.set(key1, value1)
72
+ assert_equal "STORED\r\n", m.set(key2, value2)
73
+ assert_equal "STORED\r\n", m.set(key3, value3)
74
+ assert_equal value1, m.get(key1)
75
+ assert_equal value2, m.get(key2)
76
+ assert_equal value3, m.get(key3)
77
+ assert_equal "DELETED\r\n", m.delete(key1)
78
+ assert_equal "STORED\r\n", m.set(key1, value2)
79
+ assert_equal value2, m.get(key1)
80
+ assert_equal "STORED\r\n", m.set(key2, value3)
81
+ assert_equal value3, m.get(key2)
82
+ assert_equal "STORED\r\n", m.set(key3, value1)
83
+ assert_equal value1, m.get(key3)
84
+ assert_equal({ key1 => value2, key2 => value3, key3 => value1 },
85
+ m.get_multi(key1, key2, key3))
86
+ end
87
+ rescue Exception => exp
88
+ puts exp.message
89
+ ex = exp
90
+ ensure
91
+ EM.stop
92
+ end
93
+ end
94
+ raise ex if ex
95
+ end
96
+
97
+ private
98
+
99
+ def within_em(count=1, &block)
100
+ EM.run do
101
+ count.times do
102
+ Fiber.new(&block).resume
103
+ end
104
+ end
105
+ end
106
+
107
+ def live_server?
108
+ TCPSocket.new('localhost', 11211) rescue nil
109
+ end
110
+ end
@@ -0,0 +1,1323 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'logger'
4
+ require 'stringio'
5
+ require 'test/unit'
6
+ $TESTING = true
7
+ require 'memcache'
8
+
9
+ begin
10
+ gem 'flexmock'
11
+ require 'flexmock/test_unit'
12
+ rescue LoadError => e
13
+ puts "Some tests require flexmock, please run `gem install flexmock`"
14
+ end
15
+
16
+ Thread.abort_on_exception = true
17
+
18
+ class MemCache
19
+
20
+ attr_writer :namespace
21
+ attr_writer :autofix_keys
22
+
23
+ end
24
+
25
+ class FakeSocket
26
+
27
+ attr_reader :written, :data
28
+
29
+ def initialize
30
+ @written = StringIO.new
31
+ @data = StringIO.new
32
+ end
33
+
34
+ def write(data)
35
+ @written.write data
36
+ end
37
+
38
+ def gets
39
+ @data.gets
40
+ end
41
+
42
+ def read(arg)
43
+ @data.read arg
44
+ end
45
+
46
+ end
47
+
48
+ class Test::Unit::TestCase
49
+ def requirement(bool, msg)
50
+ if bool
51
+ yield
52
+ else
53
+ puts msg
54
+ assert true
55
+ end
56
+ end
57
+
58
+ def memcached_running?
59
+ TCPSocket.new('localhost', 11211) rescue false
60
+ end
61
+
62
+ def xprofile(name, &block)
63
+ a = Time.now
64
+ block.call
65
+ Time.now - a
66
+ end
67
+
68
+ def profile(name, &block)
69
+ require 'ruby-prof'
70
+ a = Time.now
71
+ result = RubyProf.profile(&block)
72
+ time = Time.now - a
73
+ printer = RubyProf::GraphHtmlPrinter.new(result)
74
+ File.open("#{name}.html", 'w') do |f|
75
+ printer.print(f, :min_percent=>1)
76
+ end
77
+ time
78
+ end
79
+
80
+ end
81
+
82
+ class FakeServer
83
+
84
+ attr_accessor :host, :port, :socket, :weight, :multithread, :status
85
+
86
+ def initialize(socket = nil)
87
+ @closed = false
88
+ @host = 'example.com'
89
+ @port = 11211
90
+ @socket = socket || FakeSocket.new
91
+ @weight = 1
92
+ @multithread = true
93
+ @status = "CONNECTED"
94
+ end
95
+
96
+ def close
97
+ # begin
98
+ # raise "Already closed"
99
+ # rescue => e
100
+ # puts e.backtrace.join("\n")
101
+ # end
102
+ @closed = true
103
+ @socket = nil
104
+ @status = "NOT CONNECTED"
105
+ end
106
+
107
+ def alive?
108
+ # puts "I'm #{@closed ? 'dead' : 'alive'}"
109
+ !@closed
110
+ end
111
+
112
+ end
113
+
114
+ class TestMemCache < Test::Unit::TestCase
115
+
116
+ def setup
117
+ @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
118
+ end
119
+
120
+ def test_performance
121
+ requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
122
+
123
+ cache = MemCache.new(['localhost:11211',"127.0.0.1:11211"])
124
+ cache.flush_all
125
+ cache.add('a', 1, 120)
126
+ with = xprofile 'get' do
127
+ 1000.times do
128
+ cache.get('a')
129
+ end
130
+ end
131
+ puts ''
132
+ puts "1000 gets with socket timeout: #{with} sec"
133
+
134
+ cache = MemCache.new(['localhost:11211',"127.0.0.1:11211"], :timeout => nil)
135
+ cache.add('a', 1, 120)
136
+ without = xprofile 'get' do
137
+ 1000.times do
138
+ cache.get('a')
139
+ end
140
+ end
141
+ puts "1000 gets without socket timeout: #{without} sec"
142
+ end
143
+ end
144
+
145
+ def test_consistent_hashing
146
+ requirement(self.respond_to?(:flexmock), 'Flexmock is required to run this test') do
147
+
148
+ flexmock(MemCache::Server).new_instances.should_receive(:alive?).and_return(true)
149
+
150
+ # Setup a continuum of two servers
151
+ @cache.servers = ['mike1', 'mike2', 'mike3']
152
+
153
+ keys = []
154
+ 1000.times do |idx|
155
+ keys << idx.to_s
156
+ end
157
+
158
+ before_continuum = keys.map {|key| @cache.get_server_for_key(key) }
159
+
160
+ @cache.servers = ['mike1', 'mike2', 'mike3', 'mike4']
161
+
162
+ after_continuum = keys.map {|key| @cache.get_server_for_key(key) }
163
+
164
+ same_count = before_continuum.zip(after_continuum).find_all {|a| a[0].host == a[1].host }.size
165
+
166
+ # With continuum, we should see about 75% of the keys map to the same server
167
+ # With modulo, we would see about 25%.
168
+ assert same_count > 700
169
+ end
170
+ end
171
+
172
+ def test_get_multi_with_server_failure
173
+ @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace', :logger => nil #Logger.new(STDOUT)
174
+ s1 = FakeServer.new
175
+ s2 = FakeServer.new
176
+
177
+ # Write two messages to the socket to test failover
178
+ s1.socket.data.write "VALUE my_namespace:a 0 14\r\n\004\b\"\0170123456789\r\nEND\r\n"
179
+ s1.socket.data.rewind
180
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
181
+ s2.socket.data.rewind
182
+
183
+ @cache.servers = [s1, s2]
184
+
185
+ assert s1.alive?
186
+ assert s2.alive?
187
+ # a maps to s1, the rest map to s2
188
+ value = @cache.get_multi(['foo', 'bar', 'a', 'b', 'c'])
189
+ assert_equal({'a'=>'0123456789'}, value)
190
+ assert s1.alive?
191
+ assert !s2.alive?
192
+ end
193
+
194
+ def test_cache_get_with_failover
195
+ @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace', :logger => nil#Logger.new(STDOUT)
196
+ s1 = FakeServer.new
197
+ s2 = FakeServer.new
198
+
199
+ # Write two messages to the socket to test failover
200
+ s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
201
+ s1.socket.data.rewind
202
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
203
+ s2.socket.data.rewind
204
+
205
+ @cache.instance_variable_set(:@failover, true)
206
+ @cache.servers = [s1, s2]
207
+
208
+ assert s1.alive?
209
+ assert s2.alive?
210
+ @cache.get('foo')
211
+ assert s1.alive?
212
+ assert !s2.alive?
213
+ end
214
+
215
+ def test_cache_get_without_failover
216
+ s1 = FakeServer.new
217
+ s2 = FakeServer.new
218
+
219
+ s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
220
+ s1.socket.data.rewind
221
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
222
+ s2.socket.data.rewind
223
+
224
+ @cache.instance_variable_set(:@failover, false)
225
+ @cache.servers = [s1, s2]
226
+
227
+ assert s1.alive?
228
+ assert s2.alive?
229
+ e = assert_raise MemCache::MemCacheError do
230
+ @cache.get('foo')
231
+ end
232
+ assert s1.alive?
233
+ assert !s2.alive?
234
+
235
+ assert_equal "No servers available", e.message
236
+ end
237
+
238
+ def test_cache_get
239
+ server = util_setup_fake_server
240
+
241
+ assert_equal "\004\b\"\0170123456789",
242
+ @cache.cache_get(server, 'my_namespace:key')
243
+
244
+ assert_equal "get my_namespace:key\r\n",
245
+ server.socket.written.string
246
+ end
247
+
248
+ def test_cache_get_EOF
249
+ server = util_setup_fake_server
250
+ server.socket.data.string = ''
251
+
252
+ e = assert_raise IndexError do
253
+ @cache.cache_get server, 'my_namespace:key'
254
+ end
255
+
256
+ assert_equal "No connection to server (NOT CONNECTED)", e.message
257
+ end
258
+
259
+ def test_cache_get_bad_state
260
+ server = FakeServer.new
261
+
262
+ # Write two messages to the socket to test failover
263
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
264
+ server.socket.data.rewind
265
+
266
+ @cache.servers = []
267
+ @cache.servers << server
268
+
269
+ e = assert_raise IndexError do
270
+ @cache.cache_get(server, 'my_namespace:key')
271
+ end
272
+
273
+ assert_match(/#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message)
274
+
275
+ assert !server.alive?
276
+ end
277
+
278
+ def test_cache_get_miss
279
+ socket = FakeSocket.new
280
+ socket.data.write "END\r\n"
281
+ socket.data.rewind
282
+ server = FakeServer.new socket
283
+
284
+ assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
285
+
286
+ assert_equal "get my_namespace:key\r\n",
287
+ socket.written.string
288
+ end
289
+
290
+ def test_cache_get_multi
291
+ server = util_setup_fake_server
292
+ server.socket.data.write "VALUE foo 0 7\r\n"
293
+ server.socket.data.write "\004\b\"\bfoo\r\n"
294
+ server.socket.data.write "VALUE bar 0 7\r\n"
295
+ server.socket.data.write "\004\b\"\bbar\r\n"
296
+ server.socket.data.write "END\r\n"
297
+ server.socket.data.rewind
298
+
299
+ result = @cache.cache_get_multi server, 'foo bar baz'
300
+
301
+ assert_equal 2, result.length
302
+ assert_equal "\004\b\"\bfoo", result['foo']
303
+ assert_equal "\004\b\"\bbar", result['bar']
304
+ end
305
+
306
+ def test_cache_get_multi_EOF
307
+ server = util_setup_fake_server
308
+ server.socket.data.string = ''
309
+
310
+ e = assert_raise IndexError do
311
+ @cache.cache_get_multi server, 'my_namespace:key'
312
+ end
313
+
314
+ assert_equal "No connection to server (NOT CONNECTED)", e.message
315
+ end
316
+
317
+ def test_cache_get_multi_bad_state
318
+ server = FakeServer.new
319
+
320
+ # Write two messages to the socket to test failover
321
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
322
+ server.socket.data.rewind
323
+
324
+ @cache.servers = []
325
+ @cache.servers << server
326
+
327
+ e = assert_raise IndexError do
328
+ @cache.cache_get_multi server, 'my_namespace:key'
329
+ end
330
+
331
+ assert_match(/#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message)
332
+
333
+ assert !server.alive?
334
+ end
335
+
336
+ def test_multithread_error
337
+ server = FakeServer.new
338
+ server.multithread = false
339
+
340
+ @cache = MemCache.new(['localhost:1'], :multithread => false)
341
+
342
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
343
+ server.socket.data.rewind
344
+
345
+ @cache.servers = []
346
+ @cache.servers << server
347
+
348
+ assert_nothing_raised do
349
+ @cache.set 'a', 1
350
+ end
351
+
352
+ passed = true
353
+ Thread.new do
354
+ begin
355
+ @cache.set 'b', 2
356
+ passed = false
357
+ rescue MemCache::MemCacheError => me
358
+ passed = me.message =~ /multiple threads/
359
+ end
360
+ end
361
+ assert passed
362
+ end
363
+
364
+ def test_initialize
365
+ cache = MemCache.new :namespace => 'my_namespace', :readonly => true
366
+
367
+ assert_equal 'my_namespace', cache.namespace
368
+ assert_equal true, cache.readonly?
369
+ assert_equal true, cache.servers.empty?
370
+ end
371
+
372
+ def test_initialize_compatible
373
+ cache = MemCache.new ['localhost:11211', 'localhost:11212'],
374
+ :namespace => 'my_namespace', :readonly => true
375
+
376
+ assert_equal 'my_namespace', cache.namespace
377
+ assert_equal true, cache.readonly?
378
+ assert_equal false, cache.servers.empty?
379
+ end
380
+
381
+ def test_initialize_compatible_no_hash
382
+ cache = MemCache.new ['localhost:11211', 'localhost:11212']
383
+
384
+ assert_equal nil, cache.namespace
385
+ assert_equal false, cache.readonly?
386
+ assert_equal false, cache.servers.empty?
387
+ end
388
+
389
+ def test_initialize_compatible_one_server
390
+ cache = MemCache.new 'localhost:11211'
391
+
392
+ assert_equal nil, cache.namespace
393
+ assert_equal false, cache.readonly?
394
+ assert_equal false, cache.servers.empty?
395
+ end
396
+
397
+ def test_initialize_compatible_bad_arg
398
+ e = assert_raise ArgumentError do
399
+ cache = MemCache.new Object.new
400
+ end
401
+
402
+ assert_equal 'first argument must be Array, Hash or String', e.message
403
+ end
404
+
405
+ def test_initialize_multiple_servers
406
+ cache = MemCache.new %w[localhost:11211 localhost:11212],
407
+ :namespace => 'my_namespace', :readonly => true
408
+
409
+ assert_equal 'my_namespace', cache.namespace
410
+ assert_equal true, cache.readonly?
411
+ assert_equal false, cache.servers.empty?
412
+ assert !cache.instance_variable_get(:@continuum).empty?
413
+ end
414
+
415
+ def test_initialize_too_many_args
416
+ assert_raises ArgumentError do
417
+ MemCache.new 1, 2, 3
418
+ end
419
+ end
420
+
421
+ def test_decr
422
+ server = FakeServer.new
423
+ server.socket.data.write "5\r\n"
424
+ server.socket.data.rewind
425
+
426
+ @cache.servers = []
427
+ @cache.servers << server
428
+
429
+ value = @cache.decr 'key'
430
+
431
+ assert_equal "decr my_namespace:key 1\r\n",
432
+ @cache.servers.first.socket.written.string
433
+
434
+ assert_equal 5, value
435
+ end
436
+
437
+ def test_decr_not_found
438
+ server = FakeServer.new
439
+ server.socket.data.write "NOT_FOUND\r\n"
440
+ server.socket.data.rewind
441
+
442
+ @cache.servers = []
443
+ @cache.servers << server
444
+
445
+ value = @cache.decr 'key'
446
+
447
+ assert_equal "decr my_namespace:key 1\r\n",
448
+ @cache.servers.first.socket.written.string
449
+
450
+ assert_equal nil, value
451
+ end
452
+
453
+ def test_decr_space_padding
454
+ server = FakeServer.new
455
+ server.socket.data.write "5 \r\n"
456
+ server.socket.data.rewind
457
+
458
+ @cache.servers = []
459
+ @cache.servers << server
460
+
461
+ value = @cache.decr 'key'
462
+
463
+ assert_equal "decr my_namespace:key 1\r\n",
464
+ @cache.servers.first.socket.written.string
465
+
466
+ assert_equal 5, value
467
+ end
468
+
469
+ def test_get
470
+ util_setup_fake_server
471
+
472
+ value = @cache.get 'key'
473
+
474
+ assert_equal "get my_namespace:key\r\n",
475
+ @cache.servers.first.socket.written.string
476
+
477
+ assert_equal '0123456789', value
478
+ end
479
+
480
+ def test_fetch_without_a_block
481
+ server = FakeServer.new
482
+ server.socket.data.write "END\r\n"
483
+ server.socket.data.rewind
484
+
485
+ @cache.servers = [server]
486
+
487
+ flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
488
+
489
+ value = @cache.fetch('key', 1)
490
+ assert_equal nil, value
491
+ end
492
+
493
+ def test_fetch_miss
494
+ server = FakeServer.new
495
+ server.socket.data.write "END\r\n"
496
+ server.socket.data.rewind
497
+
498
+ @cache.servers = [server]
499
+
500
+ flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
501
+ flexmock(@cache).should_receive(:add).with('key', 'value', 1, false)
502
+
503
+ value = @cache.fetch('key', 1) { 'value' }
504
+
505
+ assert_equal 'value', value
506
+ end
507
+
508
+ def test_fetch_hit
509
+ server = FakeServer.new
510
+ server.socket.data.write "END\r\n"
511
+ server.socket.data.rewind
512
+
513
+ @cache.servers = [server]
514
+
515
+ flexmock(@cache).should_receive(:get).with('key', false).and_return('value')
516
+ flexmock(@cache).should_receive(:add).never
517
+
518
+ value = @cache.fetch('key', 1) { raise 'Should not be called.' }
519
+
520
+ assert_equal 'value', value
521
+ end
522
+
523
+ def test_get_bad_key
524
+ util_setup_fake_server
525
+ assert_raise ArgumentError do @cache.get 'k y' end
526
+
527
+ util_setup_fake_server
528
+ assert_raise ArgumentError do @cache.get 'k' * 250 end
529
+ end
530
+
531
+ def test_get_cache_get_IOError
532
+ socket = Object.new
533
+ def socket.write(arg) raise IOError, 'some io error'; end
534
+ server = FakeServer.new socket
535
+
536
+ @cache.servers = []
537
+ @cache.servers << server
538
+
539
+ e = assert_raise MemCache::MemCacheError do
540
+ @cache.get 'my_namespace:key'
541
+ end
542
+
543
+ assert_equal 'some io error', e.message
544
+ end
545
+
546
+ def test_get_cache_get_SystemCallError
547
+ socket = Object.new
548
+ def socket.write(arg) raise SystemCallError, 'some syscall error'; end
549
+ server = FakeServer.new socket
550
+
551
+ @cache.servers = []
552
+ @cache.servers << server
553
+
554
+ e = assert_raise MemCache::MemCacheError do
555
+ @cache.get 'my_namespace:key'
556
+ end
557
+
558
+ assert_equal 'unknown error - some syscall error', e.message.downcase
559
+ end
560
+
561
+ def test_get_no_connection
562
+ @cache.servers = 'localhost:1'
563
+ e = assert_raise MemCache::MemCacheError do
564
+ @cache.get 'key'
565
+ end
566
+
567
+ assert_match(/^No connection to server/, e.message)
568
+ end
569
+
570
+ def test_get_no_servers
571
+ @cache.servers = []
572
+ e = assert_raise MemCache::MemCacheError do
573
+ @cache.get 'key'
574
+ end
575
+
576
+ assert_equal 'No active servers', e.message
577
+ end
578
+
579
+ def test_get_multi
580
+ server = FakeServer.new
581
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
582
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
583
+ server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
584
+ server.socket.data.write "\004\b\"\0179876543210\r\n"
585
+ server.socket.data.write "END\r\n"
586
+ server.socket.data.rewind
587
+
588
+ @cache.servers = []
589
+ @cache.servers << server
590
+
591
+ values = @cache.get_multi 'key', 'keyb'
592
+
593
+ assert_equal "get my_namespace:key my_namespace:keyb\r\n",
594
+ server.socket.written.string
595
+
596
+ expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
597
+
598
+ assert_equal expected.sort, values.sort
599
+ end
600
+
601
+ def test_get_multi_raw
602
+ server = FakeServer.new
603
+ server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
604
+ server.socket.data.write "0123456789\r\n"
605
+ server.socket.data.write "VALUE my_namespace:keyb 0 10\r\n"
606
+ server.socket.data.write "9876543210\r\n"
607
+ server.socket.data.write "END\r\n"
608
+ server.socket.data.rewind
609
+
610
+ @cache.servers = []
611
+ @cache.servers << server
612
+
613
+ values = @cache.get_multi 'key', 'keyb', :raw => true
614
+
615
+ assert_equal "get my_namespace:key my_namespace:keyb\r\n",
616
+ server.socket.written.string
617
+
618
+ expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
619
+
620
+ assert_equal expected.sort, values.sort
621
+ end
622
+
623
+ def test_get_raw
624
+ server = FakeServer.new
625
+ server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
626
+ server.socket.data.write "0123456789\r\n"
627
+ server.socket.data.write "END\r\n"
628
+ server.socket.data.rewind
629
+
630
+ @cache.servers = []
631
+ @cache.servers << server
632
+
633
+
634
+ value = @cache.get 'key', true
635
+
636
+ assert_equal "get my_namespace:key\r\n",
637
+ @cache.servers.first.socket.written.string
638
+
639
+ assert_equal '0123456789', value
640
+ end
641
+
642
+ def test_get_server_for_key
643
+ server = @cache.get_server_for_key 'key'
644
+ assert_equal 'localhost', server.host
645
+ assert_equal 1, server.port
646
+ end
647
+
648
+ def test_get_server_for_key_multiple
649
+ s1 = util_setup_server @cache, 'one.example.com', ''
650
+ s2 = util_setup_server @cache, 'two.example.com', ''
651
+ @cache.servers = [s1, s2]
652
+
653
+ server = @cache.get_server_for_key 'keya'
654
+ assert_equal 'two.example.com', server.host
655
+ server = @cache.get_server_for_key 'keyb'
656
+ assert_equal 'two.example.com', server.host
657
+ server = @cache.get_server_for_key 'keyc'
658
+ assert_equal 'two.example.com', server.host
659
+ server = @cache.get_server_for_key 'keyd'
660
+ assert_equal 'one.example.com', server.host
661
+ end
662
+
663
+ def test_get_server_for_key_no_servers
664
+ @cache.servers = []
665
+
666
+ e = assert_raise MemCache::MemCacheError do
667
+ @cache.get_server_for_key 'key'
668
+ end
669
+
670
+ assert_equal 'No servers available', e.message
671
+ end
672
+
673
+ def test_get_server_for_key_spaces
674
+ e = assert_raise ArgumentError do
675
+ @cache.get_server_for_key 'space key'
676
+ end
677
+ assert_equal 'illegal character in key "space key"', e.message
678
+ end
679
+
680
+ def test_get_server_for_blank_key
681
+ e = assert_raise ArgumentError do
682
+ @cache.get_server_for_key ''
683
+ end
684
+ assert_equal 'key cannot be blank', e.message
685
+ end
686
+
687
+ def test_get_server_for_key_length
688
+ @cache.get_server_for_key 'x' * 250
689
+ long_key = 'x' * 251
690
+ e = assert_raise ArgumentError do
691
+ @cache.get_server_for_key long_key
692
+ end
693
+ assert_equal "key too long #{long_key.inspect}", e.message
694
+ end
695
+
696
+ def test_incr
697
+ server = FakeServer.new
698
+ server.socket.data.write "5\r\n"
699
+ server.socket.data.rewind
700
+
701
+ @cache.servers = []
702
+ @cache.servers << server
703
+
704
+ value = @cache.incr 'key'
705
+
706
+ assert_equal "incr my_namespace:key 1\r\n",
707
+ @cache.servers.first.socket.written.string
708
+
709
+ assert_equal 5, value
710
+ end
711
+
712
+ def test_incr_not_found
713
+ server = FakeServer.new
714
+ server.socket.data.write "NOT_FOUND\r\n"
715
+ server.socket.data.rewind
716
+
717
+ @cache.servers = []
718
+ @cache.servers << server
719
+
720
+ value = @cache.incr 'key'
721
+
722
+ assert_equal "incr my_namespace:key 1\r\n",
723
+ @cache.servers.first.socket.written.string
724
+
725
+ assert_equal nil, value
726
+ end
727
+
728
+ def test_incr_space_padding
729
+ server = FakeServer.new
730
+ server.socket.data.write "5 \r\n"
731
+ server.socket.data.rewind
732
+
733
+ @cache.servers = []
734
+ @cache.servers << server
735
+
736
+ value = @cache.incr 'key'
737
+
738
+ assert_equal "incr my_namespace:key 1\r\n",
739
+ @cache.servers.first.socket.written.string
740
+
741
+ assert_equal 5, value
742
+ end
743
+
744
+ def test_make_cache_key
745
+ assert_equal 'my_namespace:key', @cache.make_cache_key('key')
746
+ @cache.namespace = nil
747
+ assert_equal 'key', @cache.make_cache_key('key')
748
+ end
749
+
750
+ def test_make_cache_key_without_autofix
751
+ @cache.autofix_keys = false
752
+
753
+ key = "keys with more than two hundred and fifty characters can cause problems, because they get truncated and start colliding with each other. It's not a common occurrence, but when it happens is very hard to debug. the autofix option takes care of that for you"
754
+ hash = Digest::SHA1.hexdigest(key)
755
+ @cache.namespace = nil
756
+ assert_equal key, @cache.make_cache_key(key)
757
+ end
758
+
759
+ def test_make_cache_key_with_autofix
760
+ @cache.autofix_keys = true
761
+
762
+ @cache.namespace = "my_namespace"
763
+ assert_equal 'my_namespace:key', @cache.make_cache_key('key')
764
+ @cache.namespace = nil
765
+ assert_equal 'key', @cache.make_cache_key('key')
766
+
767
+ key = "keys with more than two hundred and fifty characters can cause problems, because they get truncated and start colliding with each other. It's not a common occurrence, but when it happens is very hard to debug. the autofix option takes care of that for you"
768
+ hash = Digest::SHA1.hexdigest(key)
769
+ @cache.namespace = "my_namespace"
770
+ assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
771
+ @cache.namespace = nil
772
+ assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
773
+
774
+ key = "a short key with spaces"
775
+ hash = Digest::SHA1.hexdigest(key)
776
+ @cache.namespace = "my_namespace"
777
+ assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
778
+ @cache.namespace = nil
779
+ assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
780
+
781
+ # namespace + separator + key > 250
782
+ key = 'k' * 240
783
+ hash = Digest::SHA1.hexdigest(key)
784
+ @cache.namespace = 'n' * 10
785
+ assert_equal "#{@cache.namespace}:#{hash}-autofixed", @cache.make_cache_key(key)
786
+ end
787
+
788
+ def test_servers
789
+ server = FakeServer.new
790
+ @cache.servers = []
791
+ @cache.servers << server
792
+ assert_equal [server], @cache.servers
793
+ end
794
+
795
+ def test_set
796
+ server = FakeServer.new
797
+ server.socket.data.write "STORED\r\n"
798
+ server.socket.data.rewind
799
+ @cache.servers = []
800
+ @cache.servers << server
801
+
802
+ @cache.set 'key', 'value'
803
+
804
+ dumped = Marshal.dump('value')
805
+ expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
806
+ assert_equal expected, server.socket.written.string
807
+ end
808
+
809
+ def test_set_utf8
810
+ server = FakeServer.new
811
+ server.socket.data.write "STORED\r\n"
812
+ server.socket.data.rewind
813
+ @cache.servers = []
814
+ @cache.servers << server
815
+
816
+ @cache.set 'key', 'value 启'
817
+
818
+ dumped = Marshal.dump('value 启')
819
+
820
+ expected = "set my_namespace:key 0 0 #{dumped.bytesize}\r\n"
821
+ expected << dumped
822
+ expected << "\r\n"
823
+ assert_equal expected, server.socket.written.string
824
+ end
825
+
826
+ def test_set_expiry
827
+ server = FakeServer.new
828
+ server.socket.data.write "STORED\r\n"
829
+ server.socket.data.rewind
830
+ @cache.servers = []
831
+ @cache.servers << server
832
+
833
+ @cache.set 'key', 'value', 5
834
+
835
+ dumped = Marshal.dump('value')
836
+ expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
837
+ assert_equal expected, server.socket.written.string
838
+ end
839
+
840
+ def test_set_raw
841
+ server = FakeServer.new
842
+ server.socket.data.write "STORED\r\n"
843
+ server.socket.data.rewind
844
+ @cache.servers = []
845
+ @cache.servers << server
846
+
847
+ @cache.set 'key', 'value', 0, true
848
+
849
+ expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
850
+ assert_equal expected, server.socket.written.string
851
+ end
852
+
853
+ def test_set_utf8_raw
854
+ server = FakeServer.new
855
+ server.socket.data.write "STORED\r\n"
856
+ server.socket.data.rewind
857
+ @cache.servers = []
858
+ @cache.servers << server
859
+
860
+ val = 'value 启'
861
+ @cache.set 'key', val, 0, true
862
+
863
+ expected = "set my_namespace:key 0 0 #{val.bytesize}\r\n#{val}\r\n"
864
+ assert_equal expected, server.socket.written.string
865
+ end
866
+
867
+ def test_set_readonly
868
+ cache = MemCache.new :readonly => true
869
+
870
+ e = assert_raise MemCache::MemCacheError do
871
+ cache.set 'key', 'value'
872
+ end
873
+
874
+ assert_equal 'Update of readonly cache', e.message
875
+ end
876
+
877
+ def test_check_size_on
878
+ cache = MemCache.new :check_size => true
879
+
880
+ server = FakeServer.new
881
+ server.socket.data.write "STORED\r\n"
882
+ server.socket.data.rewind
883
+
884
+ cache.servers = []
885
+ cache.servers << server
886
+
887
+ e = assert_raise MemCache::MemCacheError do
888
+ cache.set 'key', 'v' * 1048577
889
+ end
890
+
891
+ assert_equal 'Value too large, memcached can only store 1MB of data per key', e.message
892
+ end
893
+
894
+ def test_check_size_off
895
+ cache = MemCache.new :check_size => false
896
+
897
+ server = FakeServer.new
898
+ server.socket.data.write "STORED\r\n"
899
+ server.socket.data.rewind
900
+
901
+ cache.servers = []
902
+ cache.servers << server
903
+
904
+ assert_nothing_raised do
905
+ cache.set 'key', 'v' * 1048577
906
+ end
907
+ end
908
+
909
+ def test_set_too_big
910
+ server = FakeServer.new
911
+
912
+ # Write two messages to the socket to test failover
913
+ server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
914
+ server.socket.data.rewind
915
+
916
+ @cache.servers = []
917
+ @cache.servers << server
918
+
919
+ e = assert_raise MemCache::MemCacheError do
920
+ @cache.set 'key', 'v'
921
+ end
922
+
923
+ assert_match(/object too large for cache/, e.message)
924
+ end
925
+
926
+ def test_prepend
927
+ server = FakeServer.new
928
+ server.socket.data.write "STORED\r\n"
929
+ server.socket.data.rewind
930
+ @cache.servers = []
931
+ @cache.servers << server
932
+
933
+ @cache.prepend 'key', 'value'
934
+
935
+ dumped = Marshal.dump('value')
936
+
937
+ expected = "prepend my_namespace:key 0 0 5\r\nvalue\r\n"
938
+ assert_equal expected, server.socket.written.string
939
+ end
940
+
941
+ def test_append
942
+ server = FakeServer.new
943
+ server.socket.data.write "STORED\r\n"
944
+ server.socket.data.rewind
945
+ @cache.servers = []
946
+ @cache.servers << server
947
+
948
+ @cache.append 'key', 'value'
949
+
950
+ expected = "append my_namespace:key 0 0 5\r\nvalue\r\n"
951
+ assert_equal expected, server.socket.written.string
952
+ end
953
+
954
+ def test_replace
955
+ server = FakeServer.new
956
+ server.socket.data.write "STORED\r\n"
957
+ server.socket.data.rewind
958
+ @cache.servers = []
959
+ @cache.servers << server
960
+
961
+ @cache.replace 'key', 'value', 150
962
+
963
+ dumped = Marshal.dump('value')
964
+
965
+ expected = "replace my_namespace:key 0 150 #{dumped.length}\r\n#{dumped}\r\n"
966
+ assert_equal expected, server.socket.written.string
967
+ end
968
+
969
+ def test_add
970
+ server = FakeServer.new
971
+ server.socket.data.write "STORED\r\n"
972
+ server.socket.data.rewind
973
+ @cache.servers = []
974
+ @cache.servers << server
975
+
976
+ @cache.add 'key', 'value'
977
+
978
+ dumped = Marshal.dump('value')
979
+
980
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
981
+ assert_equal expected, server.socket.written.string
982
+ end
983
+
984
+ def test_add_exists
985
+ server = FakeServer.new
986
+ server.socket.data.write "NOT_STORED\r\n"
987
+ server.socket.data.rewind
988
+ @cache.servers = []
989
+ @cache.servers << server
990
+
991
+ @cache.add 'key', 'value'
992
+
993
+ dumped = Marshal.dump('value')
994
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
995
+ assert_equal expected, server.socket.written.string
996
+ end
997
+
998
+ def test_add_expiry
999
+ server = FakeServer.new
1000
+ server.socket.data.write "STORED\r\n"
1001
+ server.socket.data.rewind
1002
+ @cache.servers = []
1003
+ @cache.servers << server
1004
+
1005
+ @cache.add 'key', 'value', 5
1006
+
1007
+ dumped = Marshal.dump('value')
1008
+ expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
1009
+ assert_equal expected, server.socket.written.string
1010
+ end
1011
+
1012
+ def test_add_raw
1013
+ server = FakeServer.new
1014
+ server.socket.data.write "STORED\r\n"
1015
+ server.socket.data.rewind
1016
+ @cache.servers = []
1017
+ @cache.servers << server
1018
+
1019
+ @cache.add 'key', 'value', 0, true
1020
+
1021
+ expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
1022
+ assert_equal expected, server.socket.written.string
1023
+ end
1024
+
1025
+ def test_add_raw_int
1026
+ server = FakeServer.new
1027
+ server.socket.data.write "STORED\r\n"
1028
+ server.socket.data.rewind
1029
+ @cache.servers = []
1030
+ @cache.servers << server
1031
+
1032
+ @cache.add 'key', 12, 0, true
1033
+
1034
+ expected = "add my_namespace:key 0 0 2\r\n12\r\n"
1035
+ assert_equal expected, server.socket.written.string
1036
+ end
1037
+
1038
+ def test_add_readonly
1039
+ cache = MemCache.new :readonly => true
1040
+
1041
+ e = assert_raise MemCache::MemCacheError do
1042
+ cache.add 'key', 'value'
1043
+ end
1044
+
1045
+ assert_equal 'Update of readonly cache', e.message
1046
+ end
1047
+
1048
+ def test_delete
1049
+ server = FakeServer.new
1050
+ @cache.servers = []
1051
+ @cache.servers << server
1052
+
1053
+ @cache.delete 'key'
1054
+
1055
+ expected = "delete my_namespace:key\r\n"
1056
+ assert_equal expected, server.socket.written.string
1057
+ end
1058
+
1059
+ def test_delete_with_expiry
1060
+ server = FakeServer.new
1061
+ @cache.servers = []
1062
+ @cache.servers << server
1063
+
1064
+ @cache.delete 'key', 300
1065
+
1066
+ expected = "delete my_namespace:key\r\n"
1067
+ assert_equal expected, server.socket.written.string
1068
+ end
1069
+
1070
+ def test_flush_all
1071
+ @cache.servers = []
1072
+ 3.times { @cache.servers << FakeServer.new }
1073
+
1074
+ @cache.flush_all
1075
+
1076
+ expected = "flush_all\r\n"
1077
+ @cache.servers.each do |server|
1078
+ assert_equal expected, server.socket.written.string
1079
+ end
1080
+ end
1081
+
1082
+ def test_flush_all_with_delay
1083
+ @cache.servers = []
1084
+ 3.times { @cache.servers << FakeServer.new }
1085
+
1086
+ @cache.flush_all(10)
1087
+
1088
+ @cache.servers.each_with_index do |server, idx|
1089
+ expected = "flush_all #{idx*10}\r\n"
1090
+ assert_equal expected, server.socket.written.string
1091
+ end
1092
+ end
1093
+
1094
+ def test_flush_all_failure
1095
+ socket = FakeSocket.new
1096
+
1097
+ # Write two messages to the socket to test failover
1098
+ socket.data.write "ERROR\r\nERROR\r\n"
1099
+ socket.data.rewind
1100
+
1101
+ server = FakeServer.new socket
1102
+
1103
+ @cache.servers = []
1104
+ @cache.servers << server
1105
+
1106
+ assert_raise MemCache::MemCacheError do
1107
+ @cache.flush_all
1108
+ end
1109
+
1110
+ assert_match(/flush_all\r\n/, socket.written.string)
1111
+ end
1112
+
1113
+ def test_flush_all_for_real
1114
+ requirement(memcached_running?, 'A real memcached server must be running for testing flush_all') do
1115
+ cache = MemCache.new "localhost:11211", :namespace => "test_flush_all"
1116
+ k, v = "1234", "test"
1117
+ assert_nil cache.get(k)
1118
+ cache.set(k, v)
1119
+ assert_equal v, cache.get(k)
1120
+ cache.flush_all
1121
+ assert_nil cache.get(k)
1122
+ end
1123
+ end
1124
+
1125
+ def test_stats
1126
+ socket = FakeSocket.new
1127
+ socket.data.write "STAT pid 20188\r\nSTAT total_items 32\r\nSTAT version 1.2.3\r\nSTAT rusage_user 1:300\r\nSTAT dummy ok\r\nEND\r\n"
1128
+ socket.data.rewind
1129
+ server = FakeServer.new socket
1130
+ def server.host() 'localhost'; end
1131
+ def server.port() 11211; end
1132
+
1133
+ @cache.servers = []
1134
+ @cache.servers << server
1135
+
1136
+ expected = {
1137
+ 'localhost:11211' => {
1138
+ 'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
1139
+ 'rusage_user' => 1.0003, 'dummy' => 'ok'
1140
+ }
1141
+ }
1142
+ assert_equal expected, @cache.stats
1143
+
1144
+ assert_equal "stats\r\n", socket.written.string
1145
+ end
1146
+
1147
+ def test_basic_threaded_operations_should_work
1148
+ cache = MemCache.new :multithread => true,
1149
+ :namespace => 'my_namespace',
1150
+ :readonly => false
1151
+
1152
+ server = FakeServer.new
1153
+ server.socket.data.write "STORED\r\n"
1154
+ server.socket.data.rewind
1155
+
1156
+ cache.servers = []
1157
+ cache.servers << server
1158
+
1159
+ assert cache.multithread
1160
+
1161
+ assert_nothing_raised do
1162
+ cache.set "test", "test value"
1163
+ end
1164
+
1165
+ output = server.socket.written.string
1166
+ assert_match(/set my_namespace:test/, output)
1167
+ assert_match(/test value/, output)
1168
+ end
1169
+
1170
+ def test_namespace_separator
1171
+ cache = MemCache.new :namespace => 'ns', :namespace_separator => ''
1172
+
1173
+ server = FakeServer.new
1174
+ server.socket.data.write "STORED\r\n"
1175
+ server.socket.data.rewind
1176
+
1177
+ cache.servers = []
1178
+ cache.servers << server
1179
+
1180
+ assert_nothing_raised do
1181
+ cache.set "test", "test value"
1182
+ end
1183
+
1184
+ output = server.socket.written.string
1185
+ assert_match(/set nstest/, output)
1186
+ assert_match(/test value/, output)
1187
+ end
1188
+
1189
+ def test_basic_unthreaded_operations_should_work
1190
+ cache = MemCache.new :multithread => false,
1191
+ :namespace => 'my_namespace',
1192
+ :readonly => false
1193
+
1194
+ server = FakeServer.new
1195
+ server.socket.data.write "STORED\r\n"
1196
+ server.socket.data.rewind
1197
+
1198
+ cache.servers = []
1199
+ cache.servers << server
1200
+
1201
+ assert !cache.multithread
1202
+
1203
+ assert_nothing_raised do
1204
+ cache.set "test", "test value"
1205
+ end
1206
+
1207
+ output = server.socket.written.string
1208
+ assert_match(/set my_namespace:test/, output)
1209
+ assert_match(/test value/, output)
1210
+ end
1211
+
1212
+ def util_setup_fake_server
1213
+ server = FakeServer.new
1214
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
1215
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
1216
+ server.socket.data.write "END\r\n"
1217
+ server.socket.data.rewind
1218
+
1219
+ @cache.servers = []
1220
+ @cache.servers << server
1221
+
1222
+ return server
1223
+ end
1224
+
1225
+ def util_setup_server(memcache, host, responses)
1226
+ server = MemCache::Server.new memcache, host
1227
+ server.instance_variable_set :@sock, StringIO.new(responses)
1228
+
1229
+ @cache.servers = []
1230
+ @cache.servers << server
1231
+
1232
+ return server
1233
+ end
1234
+
1235
+ def test_crazy_multithreaded_access
1236
+ requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
1237
+
1238
+ # Use a null logger to verify logging doesn't blow up at runtime
1239
+ cache = MemCache.new(['localhost:11211', '127.0.0.1:11211'], :logger => Logger.new('/dev/null'))
1240
+ cache.flush_all
1241
+ assert_equal true, cache.multithread
1242
+ workers = []
1243
+
1244
+ cache.set('f', 'zzz')
1245
+ assert_equal "STORED\r\n", (cache.cas('f') do |value|
1246
+ value << 'z'
1247
+ end)
1248
+ assert_equal 'zzzz', cache.get('f')
1249
+
1250
+ # Have a bunch of threads perform a bunch of operations at the same time.
1251
+ # Verify the result of each operation to ensure the request and response
1252
+ # are not intermingled between threads.
1253
+ 10.times do
1254
+ workers << Thread.new do
1255
+ 100.times do
1256
+ cache.set('a', 9)
1257
+ cache.set('b', 11)
1258
+ cache.add('c', 10, 0, true)
1259
+ cache.set('d', 'a', 100, true)
1260
+ cache.set('e', 'x', 100, true)
1261
+ cache.set('f', 'zzz')
1262
+ cache.set('g', '1ብbሲg')
1263
+ cache.set('Ẽ뷽cc벼g', 'batman')
1264
+ assert_not_nil(cache.cas('f') do |value|
1265
+ value << 'z'
1266
+ end)
1267
+ cache.append('d', 'b')
1268
+ cache.prepend('e', 'y')
1269
+ assert_equal "NOT_STORED\r\n", cache.add('a', 11)
1270
+ assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
1271
+ inc = cache.incr('c', 10)
1272
+ assert_equal 0, inc % 5
1273
+ assert inc > 14
1274
+ assert cache.decr('c', 5) > 14
1275
+ assert_equal 11, cache.get('b')
1276
+ assert_equal '1ብbሲg', cache.get('g')
1277
+ assert_equal 'batman', cache.get('Ẽ뷽cc벼g')
1278
+ d = cache.get('d', true)
1279
+ assert_match(/\Aab*\Z/, d)
1280
+ e = cache.get('e', true)
1281
+ assert_match(/\Ay*x\Z/, e)
1282
+ end
1283
+ end
1284
+ end
1285
+
1286
+ workers.each { |w| w.join }
1287
+ cache.flush_all
1288
+ end
1289
+ end
1290
+
1291
+ def test_large_value
1292
+ requirement(memcached_running?, 'A memcached server must be running for live testing') do
1293
+ m = MemCache.new 'localhost'
1294
+ value = '1234567890'*500000
1295
+ assert_raises MemCache::MemCacheError do
1296
+ m.set('large_value', value)
1297
+ end
1298
+ value = '1234567890'*50000
1299
+ m.set('large_value', value)
1300
+ assert_equal value, m.get('large_value')
1301
+ end
1302
+ end
1303
+
1304
+ def test_custom_encoding
1305
+ requirement(memcached_running?, 'A memcached server must be running for live testing') do
1306
+ key = "£"
1307
+ array = [180,250,184,213]
1308
+ value = array.pack('c*')
1309
+ value.force_encoding('big5')
1310
+ assert_equal array, value.bytes.to_a
1311
+
1312
+ m = MemCache.new 'localhost'
1313
+ m.set(key, value)
1314
+ result = m.get(key)
1315
+ assert_equal(value, result)
1316
+ assert_equal(value.encoding.name, result.encoding.name)
1317
+ # m.set(key, value, true)
1318
+ # assert_equal(value, m.get(key))
1319
+ end
1320
+ end
1321
+
1322
+ end
1323
+