PageRenderTime 104ms CodeModel.GetById 2ms app.highlight 96ms RepoModel.GetById 1ms app.codeStats 0ms

/test/test_mem_cache.rb

https://github.com/bcg/memcache-client
Ruby | 989 lines | 745 code | 227 blank | 17 comment | 5 complexity | 705852088ba6955ba3571d9f64f71b5b MD5 | raw file
  1# encoding: utf-8
  2require 'logger'
  3require 'stringio'
  4require 'test/unit'
  5require 'rubygems'
  6begin
  7  gem 'flexmock'
  8  require 'flexmock/test_unit'
  9rescue LoadError => e
 10  puts "Some tests require flexmock, please run `gem install flexmock`"
 11end
 12
 13$TESTING = true
 14
 15require File.dirname(__FILE__) + '/../lib/memcache'
 16
 17class MemCache
 18
 19  attr_writer :namespace
 20
 21end
 22
 23class FakeSocket
 24
 25  attr_reader :written, :data
 26
 27  def initialize
 28    @written = StringIO.new
 29    @data = StringIO.new
 30  end
 31
 32  def write(data)
 33    @written.write data
 34  end
 35
 36  def gets
 37    @data.gets
 38  end
 39
 40  def read(arg)
 41    @data.read arg
 42  end
 43
 44end
 45
 46class Test::Unit::TestCase
 47  def requirement(bool, msg)
 48    if bool
 49      yield
 50    else
 51      puts msg
 52      assert true
 53    end
 54  end
 55  
 56  def memcached_running?
 57    TCPSocket.new('localhost', 11211) rescue false
 58  end
 59  
 60  def xprofile(name, &block)
 61    a = Time.now
 62    block.call
 63    Time.now - a
 64  end
 65
 66  def profile(name, &block)
 67    require 'ruby-prof'
 68    a = Time.now
 69    result = RubyProf.profile(&block)
 70    time = Time.now - a
 71    printer = RubyProf::GraphHtmlPrinter.new(result)
 72    File.open("#{name}.html", 'w') do |f|
 73      printer.print(f, :min_percent=>1)
 74    end
 75    time
 76  end
 77  
 78end
 79
 80class FakeServer
 81
 82  attr_reader :host, :port, :socket, :weight, :multithread, :status
 83
 84  def initialize(socket = nil)
 85    @closed = false
 86    @host = 'example.com'
 87    @port = 11211
 88    @socket = socket || FakeSocket.new
 89    @weight = 1
 90    @multithread = false
 91    @status = "CONNECTED"
 92  end
 93
 94  def close
 95    # begin
 96    #   raise "Already closed"
 97    # rescue => e
 98    #   puts e.backtrace.join("\n")
 99    # end
100    @closed = true
101    @socket = nil
102    @status = "NOT CONNECTED"
103  end
104
105  def alive?
106    # puts "I'm #{@closed ? 'dead' : 'alive'}"
107    !@closed
108  end
109
110end
111
112class TestMemCache < Test::Unit::TestCase
113
114  def setup
115    @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
116  end
117
118  def test_performance
119    requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
120      host = Socket.gethostname
121
122      cache = MemCache.new(['localhost:11211',"#{host}:11211"])
123      cache.add('a', 1, 120)
124      with = xprofile 'get' do
125        1000.times do
126          cache.get('a')
127        end
128      end
129      puts ''
130      puts "1000 gets with socket timeout: #{with} sec"
131
132      cache = MemCache.new(['localhost:11211',"#{host}:11211"], :timeout => nil)
133      cache.add('a', 1, 120)
134      without = xprofile 'get' do
135        1000.times do
136          cache.get('a')
137        end
138      end
139      puts "1000 gets without socket timeout: #{without} sec"
140
141      assert without < with
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
339    # Write two messages to the socket to test failover
340    server.socket.data.write "bogus response\r\nbogus response\r\n"
341    server.socket.data.rewind
342
343    @cache.servers = []
344    @cache.servers << server
345
346    assert_nothing_raised do
347      @cache.set 'a', 1
348    end
349
350    passed = true
351    Thread.new do
352      begin
353        @cache.set 'b', 2
354        passed = false
355      rescue MemCache::MemCacheError => me
356        passed = me.message =~ /multiple threads/
357      end
358    end
359    assert passed
360  end
361
362  def test_initialize
363    cache = MemCache.new :namespace => 'my_namespace', :readonly => true
364
365    assert_equal 'my_namespace', cache.namespace
366    assert_equal true, cache.readonly?
367    assert_equal true, cache.servers.empty?
368  end
369
370  def test_initialize_compatible
371    cache = MemCache.new ['localhost:11211', 'localhost:11212'],
372            :namespace => 'my_namespace', :readonly => true
373
374    assert_equal 'my_namespace', cache.namespace
375    assert_equal true, cache.readonly?
376    assert_equal false, cache.servers.empty?
377  end
378
379  def test_initialize_compatible_no_hash
380    cache = MemCache.new ['localhost:11211', 'localhost:11212']
381
382    assert_equal nil, cache.namespace
383    assert_equal false, cache.readonly?
384    assert_equal false, cache.servers.empty?
385  end
386
387  def test_initialize_compatible_one_server
388    cache = MemCache.new 'localhost:11211'
389
390    assert_equal nil, cache.namespace
391    assert_equal false, cache.readonly?
392    assert_equal false, cache.servers.empty?
393  end
394
395  def test_initialize_compatible_bad_arg
396    e = assert_raise ArgumentError do
397      cache = MemCache.new Object.new
398    end
399
400    assert_equal 'first argument must be Array, Hash or String', e.message
401  end
402
403  def test_initialize_multiple_servers
404    cache = MemCache.new %w[localhost:11211 localhost:11212],
405                         :namespace => 'my_namespace', :readonly => true
406
407    assert_equal 'my_namespace', cache.namespace
408    assert_equal true, cache.readonly?
409    assert_equal false, cache.servers.empty?
410    assert !cache.instance_variable_get(:@continuum).empty?
411  end
412
413  def test_initialize_too_many_args
414    assert_raises ArgumentError do
415      MemCache.new 1, 2, 3
416    end
417  end
418
419  def test_decr
420    server = FakeServer.new
421    server.socket.data.write "5\r\n"
422    server.socket.data.rewind
423
424    @cache.servers = []
425    @cache.servers << server
426
427    value = @cache.decr 'key'
428
429    assert_equal "decr my_namespace:key 1\r\n",
430                 @cache.servers.first.socket.written.string
431
432    assert_equal 5, value
433  end
434
435  def test_decr_not_found
436    server = FakeServer.new
437    server.socket.data.write "NOT_FOUND\r\n"
438    server.socket.data.rewind
439
440    @cache.servers = []
441    @cache.servers << server
442
443    value = @cache.decr 'key'
444
445    assert_equal "decr my_namespace:key 1\r\n",
446                 @cache.servers.first.socket.written.string
447
448    assert_equal nil, value
449  end
450
451  def test_decr_space_padding
452    server = FakeServer.new
453    server.socket.data.write "5 \r\n"
454    server.socket.data.rewind
455
456    @cache.servers = []
457    @cache.servers << server
458
459    value = @cache.decr 'key'
460
461    assert_equal "decr my_namespace:key 1\r\n",
462                 @cache.servers.first.socket.written.string
463
464    assert_equal 5, value
465  end
466
467  def test_get
468    util_setup_fake_server
469
470    value = @cache.get 'key'
471
472    assert_equal "get my_namespace:key\r\n",
473                 @cache.servers.first.socket.written.string
474
475    assert_equal '0123456789', value
476  end
477
478  def test_get_bad_key
479    util_setup_fake_server
480    assert_raise ArgumentError do @cache.get 'k y' end
481
482    util_setup_fake_server
483    assert_raise ArgumentError do @cache.get 'k' * 250 end
484  end
485
486  def test_get_cache_get_IOError
487    socket = Object.new
488    def socket.write(arg) raise IOError, 'some io error'; end
489    server = FakeServer.new socket
490
491    @cache.servers = []
492    @cache.servers << server
493
494    e = assert_raise MemCache::MemCacheError do
495      @cache.get 'my_namespace:key'
496    end
497
498    assert_equal 'some io error', e.message
499  end
500
501  def test_get_cache_get_SystemCallError
502    socket = Object.new
503    def socket.write(arg) raise SystemCallError, 'some syscall error'; end
504    server = FakeServer.new socket
505
506    @cache.servers = []
507    @cache.servers << server
508
509    e = assert_raise MemCache::MemCacheError do
510      @cache.get 'my_namespace:key'
511    end
512
513    assert_equal 'unknown error - some syscall error', e.message
514  end
515
516  def test_get_no_connection
517    @cache.servers = 'localhost:1'
518    e = assert_raise MemCache::MemCacheError do
519      @cache.get 'key'
520    end
521
522    assert_match /^No connection to server/, e.message
523  end
524
525  def test_get_no_servers
526    @cache.servers = []
527    e = assert_raise MemCache::MemCacheError do
528      @cache.get 'key'
529    end
530
531    assert_equal 'No active servers', e.message
532  end
533
534  def test_get_multi
535    server = FakeServer.new
536    server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
537    server.socket.data.write "\004\b\"\0170123456789\r\n"
538    server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
539    server.socket.data.write "\004\b\"\0179876543210\r\n"
540    server.socket.data.write "END\r\n"
541    server.socket.data.rewind
542
543    @cache.servers = []
544    @cache.servers << server
545
546    values = @cache.get_multi 'key', 'keyb'
547
548    assert_equal "get my_namespace:key my_namespace:keyb\r\n",
549                 server.socket.written.string
550
551    expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
552
553    assert_equal expected.sort, values.sort
554  end
555
556  def test_get_raw
557    server = FakeServer.new
558    server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
559    server.socket.data.write "0123456789\r\n"
560    server.socket.data.write "END\r\n"
561    server.socket.data.rewind
562
563    @cache.servers = []
564    @cache.servers << server
565
566
567    value = @cache.get 'key', true
568
569    assert_equal "get my_namespace:key\r\n",
570                 @cache.servers.first.socket.written.string
571
572    assert_equal '0123456789', value
573  end
574
575  def test_get_server_for_key
576    server = @cache.get_server_for_key 'key'
577    assert_equal 'localhost', server.host
578    assert_equal 1, server.port
579  end
580
581  def test_get_server_for_key_multiple
582    s1 = util_setup_server @cache, 'one.example.com', ''
583    s2 = util_setup_server @cache, 'two.example.com', ''
584    @cache.servers = [s1, s2]
585
586    server = @cache.get_server_for_key 'keya'
587    assert_equal 'two.example.com', server.host
588    server = @cache.get_server_for_key 'keyb'
589    assert_equal 'two.example.com', server.host
590    server = @cache.get_server_for_key 'keyc'
591    assert_equal 'two.example.com', server.host
592    server = @cache.get_server_for_key 'keyd'
593    assert_equal 'one.example.com', server.host
594  end
595
596  def test_get_server_for_key_no_servers
597    @cache.servers = []
598
599    e = assert_raise MemCache::MemCacheError do
600      @cache.get_server_for_key 'key'
601    end
602
603    assert_equal 'No servers available', e.message
604  end
605
606  def test_get_server_for_key_spaces
607    e = assert_raise ArgumentError do
608      @cache.get_server_for_key 'space key'
609    end
610    assert_equal 'illegal character in key "space key"', e.message
611  end
612
613  def test_get_server_for_key_length
614    @cache.get_server_for_key 'x' * 250
615    long_key = 'x' * 251
616    e = assert_raise ArgumentError do
617      @cache.get_server_for_key long_key
618    end
619    assert_equal "key too long #{long_key.inspect}", e.message
620  end
621
622  def test_incr
623    server = FakeServer.new
624    server.socket.data.write "5\r\n"
625    server.socket.data.rewind
626
627    @cache.servers = []
628    @cache.servers << server
629
630    value = @cache.incr 'key'
631
632    assert_equal "incr my_namespace:key 1\r\n",
633                 @cache.servers.first.socket.written.string
634
635    assert_equal 5, value
636  end
637
638  def test_incr_not_found
639    server = FakeServer.new
640    server.socket.data.write "NOT_FOUND\r\n"
641    server.socket.data.rewind
642
643    @cache.servers = []
644    @cache.servers << server
645
646    value = @cache.incr 'key'
647
648    assert_equal "incr my_namespace:key 1\r\n",
649                 @cache.servers.first.socket.written.string
650
651    assert_equal nil, value
652  end
653
654  def test_incr_space_padding
655    server = FakeServer.new
656    server.socket.data.write "5 \r\n"
657    server.socket.data.rewind
658
659    @cache.servers = []
660    @cache.servers << server
661
662    value = @cache.incr 'key'
663
664    assert_equal "incr my_namespace:key 1\r\n",
665                 @cache.servers.first.socket.written.string
666
667    assert_equal 5, value
668  end
669
670  def test_make_cache_key
671    assert_equal 'my_namespace:key', @cache.make_cache_key('key')
672    @cache.namespace = nil
673    assert_equal 'key', @cache.make_cache_key('key')
674  end
675
676  def test_servers
677    server = FakeServer.new
678    @cache.servers = []
679    @cache.servers << server
680    assert_equal [server], @cache.servers
681  end
682
683  def test_set
684    server = FakeServer.new
685    server.socket.data.write "STORED\r\n"
686    server.socket.data.rewind
687    @cache.servers = []
688    @cache.servers << server
689
690    @cache.set 'key', 'value'
691
692    dumped = Marshal.dump('value')
693    expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
694#    expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
695    assert_equal expected, server.socket.written.string
696  end
697
698  def test_set_expiry
699    server = FakeServer.new
700    server.socket.data.write "STORED\r\n"
701    server.socket.data.rewind
702    @cache.servers = []
703    @cache.servers << server
704
705    @cache.set 'key', 'value', 5
706
707    dumped = Marshal.dump('value')
708    expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
709    assert_equal expected, server.socket.written.string
710  end
711
712  def test_set_raw
713    server = FakeServer.new
714    server.socket.data.write "STORED\r\n"
715    server.socket.data.rewind
716    @cache.servers = []
717    @cache.servers << server
718
719    @cache.set 'key', 'value', 0, true
720
721    expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
722    assert_equal expected, server.socket.written.string
723  end
724
725  def test_set_nonblock
726    server = FakeServer.new
727    server.socket.data.write "NEVER READ"
728    server.socket.data.rewind
729    @cache.servers = []
730    @cache.servers << server
731
732    @cache.set 'key', 'value', 0, true, true
733    expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
734    assert_equal expected, server.socket.written.string
735    assert_equal "NEVER READ", server.socket.gets
736  end
737
738  def test_set_readonly
739    cache = MemCache.new :readonly => true
740
741    e = assert_raise MemCache::MemCacheError do
742      cache.set 'key', 'value'
743    end
744
745    assert_equal 'Update of readonly cache', e.message
746  end
747
748  def test_set_too_big
749    server = FakeServer.new
750
751    # Write two messages to the socket to test failover
752    server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
753    server.socket.data.rewind
754
755    @cache.servers = []
756    @cache.servers << server
757
758    e = assert_raise MemCache::MemCacheError do
759      @cache.set 'key', 'v'
760    end
761
762    assert_match /object too large for cache/, e.message
763  end
764
765  def test_add
766    server = FakeServer.new
767    server.socket.data.write "STORED\r\n"
768    server.socket.data.rewind
769    @cache.servers = []
770    @cache.servers << server
771
772    @cache.add 'key', 'value'
773    
774    dumped = Marshal.dump('value')
775
776    expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
777    assert_equal expected, server.socket.written.string
778  end
779
780  def test_add_exists
781    server = FakeServer.new
782    server.socket.data.write "NOT_STORED\r\n"
783    server.socket.data.rewind
784    @cache.servers = []
785    @cache.servers << server
786
787    @cache.add 'key', 'value'
788
789    dumped = Marshal.dump('value')
790    expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
791    assert_equal expected, server.socket.written.string
792  end
793
794  def test_add_expiry
795    server = FakeServer.new
796    server.socket.data.write "STORED\r\n"
797    server.socket.data.rewind
798    @cache.servers = []
799    @cache.servers << server
800
801    @cache.add 'key', 'value', 5
802
803    dumped = Marshal.dump('value')
804    expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
805    assert_equal expected, server.socket.written.string
806  end
807
808  def test_add_raw
809    server = FakeServer.new
810    server.socket.data.write "STORED\r\n"
811    server.socket.data.rewind
812    @cache.servers = []
813    @cache.servers << server
814
815    @cache.add 'key', 'value', 0, true
816
817    expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
818    assert_equal expected, server.socket.written.string
819  end
820
821  def test_add_raw_int
822    server = FakeServer.new
823    server.socket.data.write "STORED\r\n"
824    server.socket.data.rewind
825    @cache.servers = []
826    @cache.servers << server
827
828    @cache.add 'key', 12, 0, true
829
830    expected = "add my_namespace:key 0 0 2\r\n12\r\n"
831    assert_equal expected, server.socket.written.string
832  end
833
834  def test_add_readonly
835    cache = MemCache.new :readonly => true
836
837    e = assert_raise MemCache::MemCacheError do
838      cache.add 'key', 'value'
839    end
840
841    assert_equal 'Update of readonly cache', e.message
842  end
843
844  def test_delete
845    server = FakeServer.new
846    @cache.servers = []
847    @cache.servers << server
848    
849    @cache.delete 'key'
850    
851    expected = "delete my_namespace:key 0\r\n"
852    assert_equal expected, server.socket.written.string
853  end
854
855  def test_delete_with_expiry
856    server = FakeServer.new
857    @cache.servers = []
858    @cache.servers << server
859    
860    @cache.delete 'key', 300
861    
862    expected = "delete my_namespace:key 300\r\n"
863    assert_equal expected, server.socket.written.string
864  end
865
866  def test_flush_all
867    @cache.servers = []
868    3.times { @cache.servers << FakeServer.new }
869
870    @cache.flush_all
871
872    expected = "flush_all\r\n"
873    @cache.servers.each do |server|
874      assert_equal expected, server.socket.written.string
875    end
876  end
877
878  def test_flush_all_failure
879    socket = FakeSocket.new
880
881    # Write two messages to the socket to test failover
882    socket.data.write "ERROR\r\nERROR\r\n"
883    socket.data.rewind
884
885    server = FakeServer.new socket
886
887    @cache.servers = []
888    @cache.servers << server
889
890    assert_raise MemCache::MemCacheError do
891      @cache.flush_all
892    end
893
894    assert_match /flush_all\r\n/, socket.written.string
895  end
896
897  def test_stats
898    socket = FakeSocket.new
899    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"
900    socket.data.rewind
901    server = FakeServer.new socket
902    def server.host() 'localhost'; end
903    def server.port() 11211; end
904
905    @cache.servers = []
906    @cache.servers << server
907
908    expected = {
909      'localhost:11211' => {
910        'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
911        'rusage_user' => 1.0003, 'dummy' => 'ok'
912      }
913    }
914    assert_equal expected, @cache.stats
915
916    assert_equal "stats\r\n", socket.written.string
917  end
918
919  def test_basic_threaded_operations_should_work
920    cache = MemCache.new :multithread => true,
921                         :namespace => 'my_namespace',
922                         :readonly => false
923
924    server = FakeServer.new
925    server.socket.data.write "STORED\r\n"
926    server.socket.data.rewind
927
928    cache.servers = []
929    cache.servers << server
930
931    assert cache.multithread
932
933    assert_nothing_raised do
934      cache.set "test", "test value"
935    end
936
937    output = server.socket.written.string
938    assert_match /set my_namespace:test/, output
939    assert_match /test value/, output
940  end
941
942  def test_basic_unthreaded_operations_should_work
943    cache = MemCache.new :multithread => false,
944                         :namespace => 'my_namespace',
945                         :readonly => false
946
947    server = FakeServer.new
948    server.socket.data.write "STORED\r\n"
949    server.socket.data.rewind
950
951    cache.servers = []
952    cache.servers << server
953
954    assert !cache.multithread
955
956    assert_nothing_raised do
957      cache.set "test", "test value"
958    end
959
960    output = server.socket.written.string
961    assert_match /set my_namespace:test/, output
962    assert_match /test value/, output
963  end
964
965  def util_setup_fake_server
966    server = FakeServer.new
967    server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
968    server.socket.data.write "\004\b\"\0170123456789\r\n"
969    server.socket.data.write "END\r\n"
970    server.socket.data.rewind
971
972    @cache.servers = []
973    @cache.servers << server
974
975    return server
976  end
977
978  def util_setup_server(memcache, host, responses)
979    server = MemCache::Server.new memcache, host
980    server.instance_variable_set :@sock, StringIO.new(responses)
981
982    @cache.servers = []
983    @cache.servers << server
984
985    return server
986  end
987
988end
989