brendanlim-memcache-client 1.5.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ ##
2
+ # A utility wrapper around the MemCache client to simplify cache access. All
3
+ # methods silently ignore MemCache errors.
4
+
5
+ module Cache
6
+
7
+ ##
8
+ # Try to return a logger object that does not rely
9
+ # on ActiveRecord for logging.
10
+ def self.logger
11
+ @logger ||= if defined? Rails.logger # Rails 2.1 +
12
+ Rails.logger
13
+ elsif defined? RAILS_DEFAULT_LOGGER # Rails 1.2.2 +
14
+ RAILS_DEFAULT_LOGGER
15
+ else
16
+ ActiveRecord::Base.logger # ... very old Rails.
17
+ end
18
+ end
19
+ ##
20
+ # Returns the object at +key+ from the cache if successful, or nil if either
21
+ # the object is not in the cache or if there was an error attermpting to
22
+ # access the cache.
23
+ #
24
+ # If there is a cache miss and a block is given the result of the block will
25
+ # be stored in the cache with optional +expiry+, using the +add+ method rather
26
+ # than +set+.
27
+
28
+ def self.get(key, expiry = 0)
29
+ start_time = Time.now
30
+ value = CACHE.get key
31
+ elapsed = Time.now - start_time
32
+ logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
33
+ if value.nil? and block_given? then
34
+ value = yield
35
+ add key, value, expiry
36
+ end
37
+ value
38
+ rescue MemCache::MemCacheError => err
39
+ logger.debug "MemCache Error: #{err.message}"
40
+ if block_given? then
41
+ value = yield
42
+ put key, value, expiry
43
+ end
44
+ value
45
+ end
46
+
47
+ ##
48
+ # Sets +value+ in the cache at +key+, with an optional +expiry+ time in
49
+ # seconds.
50
+
51
+ def self.put(key, value, expiry = 0)
52
+ start_time = Time.now
53
+ CACHE.set key, value, expiry
54
+ elapsed = Time.now - start_time
55
+ logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
56
+ value
57
+ rescue MemCache::MemCacheError => err
58
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
59
+ nil
60
+ end
61
+
62
+ ##
63
+ # Sets +value+ in the cache at +key+, with an optional +expiry+ time in
64
+ # seconds. If +key+ already exists in cache, returns nil.
65
+
66
+ def self.add(key, value, expiry = 0)
67
+ start_time = Time.now
68
+ response = CACHE.add key, value, expiry
69
+ elapsed = Time.now - start_time
70
+ logger.debug('MemCache Add (%0.6f) %s' % [elapsed, key])
71
+ (response == "STORED\r\n") ? value : nil
72
+ rescue MemCache::MemCacheError => err
73
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
74
+ nil
75
+ end
76
+
77
+ ##
78
+ # Deletes +key+ from the cache in +delay+ seconds.
79
+
80
+ def self.delete(key, delay = nil)
81
+ start_time = Time.now
82
+ CACHE.delete key, delay
83
+ elapsed = Time.now - start_time
84
+ logger.debug('MemCache Delete (%0.6f) %s' %
85
+ [elapsed, key])
86
+ nil
87
+ rescue MemCache::MemCacheError => err
88
+ logger.debug "MemCache Error: #{err.message}"
89
+ nil
90
+ end
91
+
92
+ ##
93
+ # Resets all connections to MemCache servers.
94
+
95
+ def self.reset
96
+ CACHE.reset
97
+ logger.debug 'MemCache Connections Reset'
98
+ nil
99
+ end
100
+
101
+ end
102
+
@@ -0,0 +1,805 @@
1
+ # encoding: utf-8
2
+ require 'stringio'
3
+ require 'test/unit'
4
+ require 'rubygems'
5
+ begin
6
+ gem 'flexmock'
7
+ require 'flexmock/test_unit'
8
+ rescue => e
9
+ puts "Some tests require flexmock, please run `gem install flexmock`"
10
+ end
11
+
12
+ $TESTING = true
13
+
14
+ require File.dirname(__FILE__) + '/../lib/memcache'
15
+
16
+ class MemCache
17
+
18
+ attr_writer :namespace
19
+
20
+ end
21
+
22
+ class FakeSocket
23
+
24
+ attr_reader :written, :data
25
+
26
+ def initialize
27
+ @written = StringIO.new
28
+ @data = StringIO.new
29
+ end
30
+
31
+ def write(data)
32
+ @written.write data
33
+ end
34
+
35
+ def gets
36
+ @data.gets
37
+ end
38
+
39
+ def read(arg)
40
+ @data.read arg
41
+ end
42
+
43
+ end
44
+
45
+ class FakeServer
46
+
47
+ attr_reader :host, :port, :socket
48
+
49
+ def initialize(socket = nil)
50
+ @closed = false
51
+ @host = 'example.com'
52
+ @port = 11211
53
+ @socket = socket || FakeSocket.new
54
+ end
55
+
56
+ def close
57
+ @closed = true
58
+ end
59
+
60
+ def alive?
61
+ !@closed
62
+ end
63
+
64
+ end
65
+
66
+ class TestMemCache < Test::Unit::TestCase
67
+
68
+ def setup
69
+ @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
70
+ end
71
+
72
+ def test_consistent_hashing
73
+ flexmock(MemCache::Server).new_instances.should_receive(:alive?).and_return(true)
74
+
75
+ # Setup a continuum of two servers
76
+ @cache.servers = ['mike1', 'mike2', 'mike3']
77
+
78
+ keys = []
79
+ 1000.times do |idx|
80
+ keys << idx.to_s
81
+ end
82
+
83
+ before_continuum = keys.map {|key| @cache.get_server_for_key(key) }
84
+
85
+ @cache.servers = ['mike1', 'mike2', 'mike3', 'mike4']
86
+
87
+ after_continuum = keys.map {|key| @cache.get_server_for_key(key) }
88
+
89
+ same_count = before_continuum.zip(after_continuum).find_all {|a| a[0].host == a[1].host }.size
90
+
91
+ # With continuum, we should see about 75% of the keys map to the same server
92
+ # With modulo, we would see about 25%.
93
+ assert same_count > 700
94
+ end
95
+
96
+ def test_cache_get
97
+ server = util_setup_fake_server
98
+
99
+ assert_equal "\004\b\"\0170123456789",
100
+ @cache.cache_get(server, 'my_namespace:key')
101
+
102
+ assert_equal "get my_namespace:key\r\n",
103
+ server.socket.written.string
104
+ end
105
+
106
+ def test_cache_get_EOF
107
+ server = util_setup_fake_server
108
+ server.socket.data.string = ''
109
+
110
+ e = assert_raise MemCache::MemCacheError do
111
+ @cache.cache_get server, 'my_namespace:key'
112
+ end
113
+
114
+ assert_equal "lost connection to example.com:11211", e.message
115
+ end
116
+
117
+ def test_cache_get_bad_state
118
+ server = FakeServer.new
119
+
120
+ # Write two messages to the socket to test failover
121
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
122
+ server.socket.data.rewind
123
+
124
+ @cache.servers = []
125
+ @cache.servers << server
126
+
127
+ e = assert_raise MemCache::MemCacheError do
128
+ @cache.cache_get(server, 'my_namespace:key')
129
+ end
130
+
131
+ assert_match /#{Regexp.quote 'unexpected response "bogus response\r\n"'}/, e.message
132
+
133
+ assert !server.alive?
134
+
135
+ assert_match /get my_namespace:key\r\n/, server.socket.written.string
136
+ end
137
+
138
+ def test_cache_get_miss
139
+ socket = FakeSocket.new
140
+ socket.data.write "END\r\n"
141
+ socket.data.rewind
142
+ server = FakeServer.new socket
143
+
144
+ assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
145
+
146
+ assert_equal "get my_namespace:key\r\n",
147
+ socket.written.string
148
+ end
149
+
150
+ def test_cache_get_multi
151
+ server = util_setup_fake_server
152
+ server.socket.data.write "VALUE foo 0 7\r\n"
153
+ server.socket.data.write "\004\b\"\bfoo\r\n"
154
+ server.socket.data.write "VALUE bar 0 7\r\n"
155
+ server.socket.data.write "\004\b\"\bbar\r\n"
156
+ server.socket.data.write "END\r\n"
157
+ server.socket.data.rewind
158
+
159
+ result = @cache.cache_get_multi server, 'foo bar baz'
160
+
161
+ assert_equal 2, result.length
162
+ assert_equal "\004\b\"\bfoo", result['foo']
163
+ assert_equal "\004\b\"\bbar", result['bar']
164
+ end
165
+
166
+ def test_cache_get_multi_EOF
167
+ server = util_setup_fake_server
168
+ server.socket.data.string = ''
169
+
170
+ e = assert_raise MemCache::MemCacheError do
171
+ @cache.cache_get_multi server, 'my_namespace:key'
172
+ end
173
+
174
+ assert_equal "lost connection to example.com:11211", e.message
175
+ end
176
+
177
+ def test_cache_get_multi_bad_state
178
+ server = FakeServer.new
179
+
180
+ # Write two messages to the socket to test failover
181
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
182
+ server.socket.data.rewind
183
+
184
+ @cache.servers = []
185
+ @cache.servers << server
186
+
187
+ e = assert_raise MemCache::MemCacheError do
188
+ @cache.cache_get_multi server, 'my_namespace:key'
189
+ end
190
+
191
+ assert_match /#{Regexp.quote 'unexpected response "bogus response\r\n"'}/, e.message
192
+
193
+ assert !server.alive?
194
+
195
+ assert_match /get my_namespace:key\r\n/, server.socket.written.string
196
+ end
197
+
198
+ def test_initialize
199
+ cache = MemCache.new :namespace => 'my_namespace', :readonly => true
200
+
201
+ assert_equal 'my_namespace', cache.namespace
202
+ assert_equal true, cache.readonly?
203
+ assert_equal true, cache.servers.empty?
204
+ end
205
+
206
+ def test_initialize_compatible
207
+ cache = MemCache.new ['localhost:11211', 'localhost:11212'],
208
+ :namespace => 'my_namespace', :readonly => true
209
+
210
+ assert_equal 'my_namespace', cache.namespace
211
+ assert_equal true, cache.readonly?
212
+ assert_equal false, cache.servers.empty?
213
+ end
214
+
215
+ def test_initialize_compatible_no_hash
216
+ cache = MemCache.new ['localhost:11211', 'localhost:11212']
217
+
218
+ assert_equal nil, cache.namespace
219
+ assert_equal false, cache.readonly?
220
+ assert_equal false, cache.servers.empty?
221
+ end
222
+
223
+ def test_initialize_compatible_one_server
224
+ cache = MemCache.new 'localhost:11211'
225
+
226
+ assert_equal nil, cache.namespace
227
+ assert_equal false, cache.readonly?
228
+ assert_equal false, cache.servers.empty?
229
+ end
230
+
231
+ def test_initialize_compatible_bad_arg
232
+ e = assert_raise ArgumentError do
233
+ cache = MemCache.new Object.new
234
+ end
235
+
236
+ assert_equal 'first argument must be Array, Hash or String', e.message
237
+ end
238
+
239
+ def test_initialize_multiple_servers
240
+ cache = MemCache.new %w[localhost:11211 localhost:11212],
241
+ :namespace => 'my_namespace', :readonly => true
242
+
243
+ assert_equal 'my_namespace', cache.namespace
244
+ assert_equal true, cache.readonly?
245
+ assert_equal false, cache.servers.empty?
246
+ assert !cache.instance_variable_get(:@continuum).empty?
247
+ end
248
+
249
+ def test_initialize_too_many_args
250
+ assert_raises ArgumentError do
251
+ MemCache.new 1, 2, 3
252
+ end
253
+ end
254
+
255
+ def test_decr
256
+ server = FakeServer.new
257
+ server.socket.data.write "5\r\n"
258
+ server.socket.data.rewind
259
+
260
+ @cache.servers = []
261
+ @cache.servers << server
262
+
263
+ value = @cache.decr 'key'
264
+
265
+ assert_equal "decr my_namespace:key 1\r\n",
266
+ @cache.servers.first.socket.written.string
267
+
268
+ assert_equal 5, value
269
+ end
270
+
271
+ def test_decr_not_found
272
+ server = FakeServer.new
273
+ server.socket.data.write "NOT_FOUND\r\n"
274
+ server.socket.data.rewind
275
+
276
+ @cache.servers = []
277
+ @cache.servers << server
278
+
279
+ value = @cache.decr 'key'
280
+
281
+ assert_equal "decr my_namespace:key 1\r\n",
282
+ @cache.servers.first.socket.written.string
283
+
284
+ assert_equal nil, value
285
+ end
286
+
287
+ def test_decr_space_padding
288
+ server = FakeServer.new
289
+ server.socket.data.write "5 \r\n"
290
+ server.socket.data.rewind
291
+
292
+ @cache.servers = []
293
+ @cache.servers << server
294
+
295
+ value = @cache.decr 'key'
296
+
297
+ assert_equal "decr my_namespace:key 1\r\n",
298
+ @cache.servers.first.socket.written.string
299
+
300
+ assert_equal 5, value
301
+ end
302
+
303
+ def test_get
304
+ util_setup_fake_server
305
+
306
+ value = @cache.get 'key'
307
+
308
+ assert_equal "get my_namespace:key\r\n",
309
+ @cache.servers.first.socket.written.string
310
+
311
+ assert_equal '0123456789', value
312
+ end
313
+
314
+ def test_get_bad_key
315
+ util_setup_fake_server
316
+ assert_raise ArgumentError do @cache.get 'k y' end
317
+
318
+ util_setup_fake_server
319
+ assert_raise ArgumentError do @cache.get 'k' * 250 end
320
+ end
321
+
322
+ def test_get_cache_get_IOError
323
+ socket = Object.new
324
+ def socket.write(arg) raise IOError, 'some io error'; end
325
+ server = FakeServer.new socket
326
+
327
+ @cache.servers = []
328
+ @cache.servers << server
329
+
330
+ e = assert_raise MemCache::MemCacheError do
331
+ @cache.get 'my_namespace:key'
332
+ end
333
+
334
+ assert_equal 'some io error', e.message
335
+ end
336
+
337
+ def test_get_cache_get_SystemCallError
338
+ socket = Object.new
339
+ def socket.write(arg) raise SystemCallError, 'some syscall error'; end
340
+ server = FakeServer.new socket
341
+
342
+ @cache.servers = []
343
+ @cache.servers << server
344
+
345
+ e = assert_raise MemCache::MemCacheError do
346
+ @cache.get 'my_namespace:key'
347
+ end
348
+
349
+ assert_equal 'unknown error - some syscall error', e.message
350
+ end
351
+
352
+ def test_get_no_connection
353
+ @cache.servers = 'localhost:1'
354
+ e = assert_raise MemCache::MemCacheError do
355
+ @cache.get 'key'
356
+ end
357
+
358
+ assert_match /^No connection to server/, e.message
359
+ end
360
+
361
+ def test_get_no_servers
362
+ @cache.servers = []
363
+ e = assert_raise MemCache::MemCacheError do
364
+ @cache.get 'key'
365
+ end
366
+
367
+ assert_equal 'No active servers', e.message
368
+ end
369
+
370
+ def test_get_multi
371
+ server = FakeServer.new
372
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
373
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
374
+ server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
375
+ server.socket.data.write "\004\b\"\0179876543210\r\n"
376
+ server.socket.data.write "END\r\n"
377
+ server.socket.data.rewind
378
+
379
+ @cache.servers = []
380
+ @cache.servers << server
381
+
382
+ values = @cache.get_multi 'key', 'keyb'
383
+
384
+ assert_equal "get my_namespace:key my_namespace:keyb\r\n",
385
+ server.socket.written.string
386
+
387
+ expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
388
+
389
+ assert_equal expected.sort, values.sort
390
+ end
391
+
392
+ def test_get_raw
393
+ server = FakeServer.new
394
+ server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
395
+ server.socket.data.write "0123456789\r\n"
396
+ server.socket.data.write "END\r\n"
397
+ server.socket.data.rewind
398
+
399
+ @cache.servers = []
400
+ @cache.servers << server
401
+
402
+
403
+ value = @cache.get 'key', true
404
+
405
+ assert_equal "get my_namespace:key\r\n",
406
+ @cache.servers.first.socket.written.string
407
+
408
+ assert_equal '0123456789', value
409
+ end
410
+
411
+ def test_get_server_for_key
412
+ server = @cache.get_server_for_key 'key'
413
+ assert_equal 'localhost', server.host
414
+ assert_equal 1, server.port
415
+ end
416
+
417
+ def test_get_server_for_key_multiple
418
+ s1 = util_setup_server @cache, 'one.example.com', ''
419
+ s2 = util_setup_server @cache, 'two.example.com', ''
420
+ @cache.servers = [s1, s2]
421
+
422
+ server = @cache.get_server_for_key 'keya'
423
+ assert_equal 'two.example.com', server.host
424
+ server = @cache.get_server_for_key 'keyb'
425
+ assert_equal 'two.example.com', server.host
426
+ server = @cache.get_server_for_key 'keyc'
427
+ assert_equal 'two.example.com', server.host
428
+ server = @cache.get_server_for_key 'keyd'
429
+ assert_equal 'one.example.com', server.host
430
+ end
431
+
432
+ def test_get_server_for_key_no_servers
433
+ @cache.servers = []
434
+
435
+ e = assert_raise MemCache::MemCacheError do
436
+ @cache.get_server_for_key 'key'
437
+ end
438
+
439
+ assert_equal 'No servers available', e.message
440
+ end
441
+
442
+ def test_get_server_for_key_spaces
443
+ e = assert_raise ArgumentError do
444
+ @cache.get_server_for_key 'space key'
445
+ end
446
+ assert_equal 'illegal character in key "space key"', e.message
447
+ end
448
+
449
+ def test_get_server_for_key_length
450
+ @cache.get_server_for_key 'x' * 250
451
+ long_key = 'x' * 251
452
+ e = assert_raise ArgumentError do
453
+ @cache.get_server_for_key long_key
454
+ end
455
+ assert_equal "key too long #{long_key.inspect}", e.message
456
+ end
457
+
458
+ def test_incr
459
+ server = FakeServer.new
460
+ server.socket.data.write "5\r\n"
461
+ server.socket.data.rewind
462
+
463
+ @cache.servers = []
464
+ @cache.servers << server
465
+
466
+ value = @cache.incr 'key'
467
+
468
+ assert_equal "incr my_namespace:key 1\r\n",
469
+ @cache.servers.first.socket.written.string
470
+
471
+ assert_equal 5, value
472
+ end
473
+
474
+ def test_incr_not_found
475
+ server = FakeServer.new
476
+ server.socket.data.write "NOT_FOUND\r\n"
477
+ server.socket.data.rewind
478
+
479
+ @cache.servers = []
480
+ @cache.servers << server
481
+
482
+ value = @cache.incr 'key'
483
+
484
+ assert_equal "incr my_namespace:key 1\r\n",
485
+ @cache.servers.first.socket.written.string
486
+
487
+ assert_equal nil, value
488
+ end
489
+
490
+ def test_incr_space_padding
491
+ server = FakeServer.new
492
+ server.socket.data.write "5 \r\n"
493
+ server.socket.data.rewind
494
+
495
+ @cache.servers = []
496
+ @cache.servers << server
497
+
498
+ value = @cache.incr 'key'
499
+
500
+ assert_equal "incr my_namespace:key 1\r\n",
501
+ @cache.servers.first.socket.written.string
502
+
503
+ assert_equal 5, value
504
+ end
505
+
506
+ def test_make_cache_key
507
+ assert_equal 'my_namespace:key', @cache.make_cache_key('key')
508
+ @cache.namespace = nil
509
+ assert_equal 'key', @cache.make_cache_key('key')
510
+ end
511
+
512
+ def test_servers
513
+ server = FakeServer.new
514
+ @cache.servers = []
515
+ @cache.servers << server
516
+ assert_equal [server], @cache.servers
517
+ end
518
+
519
+ def test_servers_equals_type_error
520
+ e = assert_raise TypeError do
521
+ @cache.servers = [Object.new]
522
+ end
523
+
524
+ assert_equal 'cannot convert Object into MemCache::Server', e.message
525
+ end
526
+
527
+ def test_set
528
+ server = FakeServer.new
529
+ server.socket.data.write "STORED\r\n"
530
+ server.socket.data.rewind
531
+ @cache.servers = []
532
+ @cache.servers << server
533
+
534
+ @cache.set 'key', 'value'
535
+
536
+ dumped = Marshal.dump('value')
537
+ expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
538
+ # expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
539
+ assert_equal expected, server.socket.written.string
540
+ end
541
+
542
+ def test_set_expiry
543
+ server = FakeServer.new
544
+ server.socket.data.write "STORED\r\n"
545
+ server.socket.data.rewind
546
+ @cache.servers = []
547
+ @cache.servers << server
548
+
549
+ @cache.set 'key', 'value', 5
550
+
551
+ dumped = Marshal.dump('value')
552
+ expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
553
+ assert_equal expected, server.socket.written.string
554
+ end
555
+
556
+ def test_set_raw
557
+ server = FakeServer.new
558
+ server.socket.data.write "STORED\r\n"
559
+ server.socket.data.rewind
560
+ @cache.servers = []
561
+ @cache.servers << server
562
+
563
+ @cache.set 'key', 'value', 0, true
564
+
565
+ expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
566
+ assert_equal expected, server.socket.written.string
567
+ end
568
+
569
+ def test_set_readonly
570
+ cache = MemCache.new :readonly => true
571
+
572
+ e = assert_raise MemCache::MemCacheError do
573
+ cache.set 'key', 'value'
574
+ end
575
+
576
+ assert_equal 'Update of readonly cache', e.message
577
+ end
578
+
579
+ def test_set_too_big
580
+ server = FakeServer.new
581
+
582
+ # Write two messages to the socket to test failover
583
+ server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
584
+ server.socket.data.rewind
585
+
586
+ @cache.servers = []
587
+ @cache.servers << server
588
+
589
+ e = assert_raise MemCache::MemCacheError do
590
+ @cache.set 'key', 'v'
591
+ end
592
+
593
+ assert_match /object too large for cache/, e.message
594
+ end
595
+
596
+ def test_add
597
+ server = FakeServer.new
598
+ server.socket.data.write "STORED\r\n"
599
+ server.socket.data.rewind
600
+ @cache.servers = []
601
+ @cache.servers << server
602
+
603
+ @cache.add 'key', 'value'
604
+
605
+ dumped = Marshal.dump('value')
606
+
607
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
608
+ assert_equal expected, server.socket.written.string
609
+ end
610
+
611
+ def test_add_exists
612
+ server = FakeServer.new
613
+ server.socket.data.write "NOT_STORED\r\n"
614
+ server.socket.data.rewind
615
+ @cache.servers = []
616
+ @cache.servers << server
617
+
618
+ @cache.add 'key', 'value'
619
+
620
+ dumped = Marshal.dump('value')
621
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
622
+ assert_equal expected, server.socket.written.string
623
+ end
624
+
625
+ def test_add_expiry
626
+ server = FakeServer.new
627
+ server.socket.data.write "STORED\r\n"
628
+ server.socket.data.rewind
629
+ @cache.servers = []
630
+ @cache.servers << server
631
+
632
+ @cache.add 'key', 'value', 5
633
+
634
+ dumped = Marshal.dump('value')
635
+ expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
636
+ assert_equal expected, server.socket.written.string
637
+ end
638
+
639
+ def test_add_raw
640
+ server = FakeServer.new
641
+ server.socket.data.write "STORED\r\n"
642
+ server.socket.data.rewind
643
+ @cache.servers = []
644
+ @cache.servers << server
645
+
646
+ @cache.add 'key', 'value', 0, true
647
+
648
+ expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
649
+ assert_equal expected, server.socket.written.string
650
+ end
651
+
652
+ def test_add_readonly
653
+ cache = MemCache.new :readonly => true
654
+
655
+ e = assert_raise MemCache::MemCacheError do
656
+ cache.add 'key', 'value'
657
+ end
658
+
659
+ assert_equal 'Update of readonly cache', e.message
660
+ end
661
+
662
+ def test_delete
663
+ server = FakeServer.new
664
+ @cache.servers = []
665
+ @cache.servers << server
666
+
667
+ @cache.delete 'key'
668
+
669
+ expected = "delete my_namespace:key 0\r\n"
670
+ assert_equal expected, server.socket.written.string
671
+ end
672
+
673
+ def test_delete_with_expiry
674
+ server = FakeServer.new
675
+ @cache.servers = []
676
+ @cache.servers << server
677
+
678
+ @cache.delete 'key', 300
679
+
680
+ expected = "delete my_namespace:key 300\r\n"
681
+ assert_equal expected, server.socket.written.string
682
+ end
683
+
684
+ def test_flush_all
685
+ @cache.servers = []
686
+ 3.times { @cache.servers << FakeServer.new }
687
+
688
+ @cache.flush_all
689
+
690
+ expected = "flush_all\r\n"
691
+ @cache.servers.each do |server|
692
+ assert_equal expected, server.socket.written.string
693
+ end
694
+ end
695
+
696
+ def test_flush_all_failure
697
+ socket = FakeSocket.new
698
+
699
+ # Write two messages to the socket to test failover
700
+ socket.data.write "ERROR\r\nERROR\r\n"
701
+ socket.data.rewind
702
+
703
+ server = FakeServer.new socket
704
+
705
+ @cache.servers = []
706
+ @cache.servers << server
707
+
708
+ assert_raise MemCache::MemCacheError do
709
+ @cache.flush_all
710
+ end
711
+
712
+ assert_match /flush_all\r\n/, socket.written.string
713
+ end
714
+
715
+ def test_stats
716
+ socket = FakeSocket.new
717
+ 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"
718
+ socket.data.rewind
719
+ server = FakeServer.new socket
720
+ def server.host() 'localhost'; end
721
+ def server.port() 11211; end
722
+
723
+ @cache.servers = []
724
+ @cache.servers << server
725
+
726
+ expected = {
727
+ 'localhost:11211' => {
728
+ 'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
729
+ 'rusage_user' => 1.0003, 'dummy' => 'ok'
730
+ }
731
+ }
732
+ assert_equal expected, @cache.stats
733
+
734
+ assert_equal "stats\r\n", socket.written.string
735
+ end
736
+
737
+ def test_basic_threaded_operations_should_work
738
+ cache = MemCache.new :multithread => true,
739
+ :namespace => 'my_namespace',
740
+ :readonly => false
741
+
742
+ server = FakeServer.new
743
+ server.socket.data.write "STORED\r\n"
744
+ server.socket.data.rewind
745
+
746
+ cache.servers = []
747
+ cache.servers << server
748
+
749
+ assert cache.multithread
750
+
751
+ assert_nothing_raised do
752
+ cache.set "test", "test value"
753
+ end
754
+
755
+ # TODO Fails in 1.9
756
+ assert_match /set my_namespace:test.*\r\n.*test value.*\r\n/, server.socket.written.string
757
+ end
758
+
759
+ def test_basic_unthreaded_operations_should_work
760
+ cache = MemCache.new :multithread => false,
761
+ :namespace => 'my_namespace',
762
+ :readonly => false
763
+
764
+ server = FakeServer.new
765
+ server.socket.data.write "STORED\r\n"
766
+ server.socket.data.rewind
767
+
768
+ cache.servers = []
769
+ cache.servers << server
770
+
771
+ assert !cache.multithread
772
+
773
+ assert_nothing_raised do
774
+ cache.set "test", "test value"
775
+ end
776
+
777
+ # TODO Fails in 1.9
778
+ assert_match /set my_namespace:test.*\r\n.*test value\r\n/, server.socket.written.string
779
+ end
780
+
781
+ def util_setup_fake_server
782
+ server = FakeServer.new
783
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
784
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
785
+ server.socket.data.write "END\r\n"
786
+ server.socket.data.rewind
787
+
788
+ @cache.servers = []
789
+ @cache.servers << server
790
+
791
+ return server
792
+ end
793
+
794
+ def util_setup_server(memcache, host, responses)
795
+ server = MemCache::Server.new memcache, host
796
+ server.instance_variable_set :@sock, StringIO.new(responses)
797
+
798
+ @cache.servers = []
799
+ @cache.servers << server
800
+
801
+ return server
802
+ end
803
+
804
+ end
805
+