PageRenderTime 106ms CodeModel.GetById 2ms app.highlight 98ms RepoModel.GetById 3ms app.codeStats 0ms

/test/test_mem_cache.rb

https://github.com/ryland/memcache-client
Ruby | 758 lines | 702 code | 56 blank | 0 comment | 1 complexity | 9d1bea5c1c86bdfa63fda0c55b285726 MD5 | raw file
  1require 'stringio'
  2require 'test/unit'
  3require 'rubygems'
  4require 'test/zentest_assertions'
  5
  6$TESTING = true
  7
  8require 'lib/memcache'
  9
 10class MemCache
 11
 12  attr_writer :namespace
 13
 14end
 15
 16class FakeSocket
 17
 18  attr_reader :written, :data
 19
 20  def initialize
 21    @written = StringIO.new
 22    @data = StringIO.new
 23  end
 24
 25  def write(data)
 26    @written.write data
 27  end
 28
 29  def gets
 30    @data.gets
 31  end
 32
 33  def read(arg)
 34    @data.read arg
 35  end
 36
 37end
 38
 39class FakeServer
 40
 41  attr_reader :host, :port, :socket
 42
 43  def initialize(socket = nil)
 44    @closed = false
 45    @host = 'example.com'
 46    @port = 11211
 47    @socket = socket || FakeSocket.new
 48  end
 49
 50  def close
 51    @closed = true
 52  end
 53
 54  def alive?
 55    !@closed
 56  end
 57
 58end
 59
 60class TestMemCache < Test::Unit::TestCase
 61
 62  def setup
 63    @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
 64  end
 65
 66  def test_cache_get
 67    server = util_setup_fake_server
 68
 69    assert_equal "\004\b\"\0170123456789",
 70                 @cache.cache_get(server, 'my_namespace:key')
 71
 72    assert_equal "get my_namespace:key\r\n",
 73                 server.socket.written.string
 74  end
 75
 76  def test_cache_get_EOF
 77    server = util_setup_fake_server
 78    server.socket.data.string = ''
 79
 80    e = assert_raise MemCache::MemCacheError do
 81      @cache.cache_get server, 'my_namespace:key'
 82    end
 83
 84    assert_equal "lost connection to example.com:11211", e.message
 85  end
 86
 87  def test_cache_get_bad_state
 88    server = FakeServer.new
 89    server.socket.data.write "bogus response\r\n"
 90    server.socket.data.rewind
 91
 92    @cache.servers = []
 93    @cache.servers << server
 94
 95    e = assert_raise MemCache::MemCacheError do
 96      @cache.cache_get(server, 'my_namespace:key')
 97    end
 98
 99    assert_equal "unexpected response \"bogus response\\r\\n\"", e.message
100
101    deny server.alive?
102
103    assert_equal "get my_namespace:key\r\n",
104                 server.socket.written.string
105  end
106
107  def test_cache_get_miss
108    socket = FakeSocket.new
109    socket.data.write "END\r\n"
110    socket.data.rewind
111    server = FakeServer.new socket
112
113    assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
114
115    assert_equal "get my_namespace:key\r\n",
116                 socket.written.string
117  end
118
119  def test_cache_get_multi
120    server = util_setup_fake_server
121    server.socket.data.write "VALUE foo 0 7\r\n"
122    server.socket.data.write "\004\b\"\bfoo\r\n"
123    server.socket.data.write "VALUE bar 0 7\r\n"
124    server.socket.data.write "\004\b\"\bbar\r\n"
125    server.socket.data.write "END\r\n"
126    server.socket.data.rewind
127
128    result = @cache.cache_get_multi server, 'foo bar baz'
129
130    assert_equal 2, result.length
131    assert_equal "\004\b\"\bfoo", result['foo']
132    assert_equal "\004\b\"\bbar", result['bar']
133  end
134
135  def test_cache_get_multi_EOF
136    server = util_setup_fake_server
137    server.socket.data.string = ''
138
139    e = assert_raise MemCache::MemCacheError do
140      @cache.cache_get_multi server, 'my_namespace:key'
141    end
142
143    assert_equal "lost connection to example.com:11211", e.message
144  end
145
146  def test_cache_get_multi_bad_state
147    server = FakeServer.new
148    server.socket.data.write "bogus response\r\n"
149    server.socket.data.rewind
150
151    @cache.servers = []
152    @cache.servers << server
153
154    e = assert_raise MemCache::MemCacheError do
155      @cache.cache_get_multi server, 'my_namespace:key'
156    end
157
158    assert_equal "unexpected response \"bogus response\\r\\n\"", e.message
159
160    deny server.alive?
161
162    assert_equal "get my_namespace:key\r\n",
163                 server.socket.written.string
164  end
165
166  def test_crc32_ITU_T
167    assert_equal 0, ''.crc32_ITU_T
168    assert_equal 1260851911, 'my_namespace:key'.crc32_ITU_T
169  end
170
171  def test_initialize
172    cache = MemCache.new :namespace => 'my_namespace', :readonly => true
173
174    assert_equal 'my_namespace', cache.namespace
175    assert_equal true, cache.readonly?
176    assert_equal true, cache.servers.empty?
177  end
178
179  def test_initialize_compatible
180    cache = MemCache.new ['localhost:11211', 'localhost:11212'],
181            :namespace => 'my_namespace', :readonly => true
182
183    assert_equal 'my_namespace', cache.namespace
184    assert_equal true, cache.readonly?
185    assert_equal false, cache.servers.empty?
186    assert_equal true, cache.servers.first.tcp_nodelay
187  end
188
189  def test_initialize_compatible_no_hash
190    cache = MemCache.new ['localhost:11211', 'localhost:11212']
191
192    assert_equal nil, cache.namespace
193    assert_equal false, cache.readonly?
194    assert_equal false, cache.servers.empty?
195  end
196
197  def test_initialize_compatible_one_server
198    cache = MemCache.new 'localhost:11211'
199
200    assert_equal nil, cache.namespace
201    assert_equal false, cache.readonly?
202    assert_equal false, cache.servers.empty?
203  end
204
205  def test_initialize_compatible_bad_arg
206    e = assert_raise ArgumentError do
207      cache = MemCache.new Object.new
208    end
209
210    assert_equal 'first argument must be Array, Hash or String', e.message
211  end
212
213  def test_initialize_multiple_servers
214    cache = MemCache.new %w[localhost:11211 localhost:11212],
215                         :namespace => 'my_namespace', :readonly => true
216
217    assert_equal 'my_namespace', cache.namespace
218    assert_equal true, cache.readonly?
219    assert_equal false, cache.servers.empty?
220    deny_empty cache.instance_variable_get(:@buckets)
221  end
222
223  def test_initialize_with_server_options
224    cache = MemCache.new %w[localhost:11211 localhost:11212],
225                         :namespace => 'my_namespace', :retry_delay => 15.0, 
226                         :connect_timeout => 5.0
227
228    assert_equal 'my_namespace', cache.namespace
229    assert_equal false, cache.servers.empty?
230    cache.servers.each do |s|
231      assert_equal 5.0, s.connect_timeout
232      assert_equal 15.0, s.retry_delay
233    end
234  end
235
236  def test_initialize_too_many_args
237    assert_raises ArgumentError do
238      MemCache.new 1, 2, 3
239    end
240  end
241
242  def test_decr
243    server = FakeServer.new
244    server.socket.data.write "5\r\n"
245    server.socket.data.rewind
246
247    @cache.servers = []
248    @cache.servers << server
249
250    value = @cache.decr 'key'
251
252    assert_equal "decr my_namespace:key 1\r\n",
253                 @cache.servers.first.socket.written.string
254
255    assert_equal 5, value
256  end
257
258  def test_decr_not_found
259    server = FakeServer.new
260    server.socket.data.write "NOT_FOUND\r\n"
261    server.socket.data.rewind
262
263    @cache.servers = []
264    @cache.servers << server
265
266    value = @cache.decr 'key'
267
268    assert_equal "decr my_namespace:key 1\r\n",
269                 @cache.servers.first.socket.written.string
270
271    assert_equal nil, value
272  end
273
274  def test_decr_space_padding
275    server = FakeServer.new
276    server.socket.data.write "5 \r\n"
277    server.socket.data.rewind
278
279    @cache.servers = []
280    @cache.servers << server
281
282    value = @cache.decr 'key'
283
284    assert_equal "decr my_namespace:key 1\r\n",
285                 @cache.servers.first.socket.written.string
286
287    assert_equal 5, value
288  end
289
290  def test_get
291    util_setup_fake_server
292
293    value = @cache.get 'key'
294
295    assert_equal "get my_namespace:key\r\n",
296                 @cache.servers.first.socket.written.string
297
298    assert_equal '0123456789', value
299  end
300
301  def test_get_bad_key
302    util_setup_fake_server
303    assert_raise ArgumentError do @cache.get 'k y' end
304
305    util_setup_fake_server
306    assert_raise ArgumentError do @cache.get 'k' * 250 end
307  end
308
309  def test_get_cache_get_IOError
310    socket = Object.new
311    def socket.write(arg) raise IOError, 'some io error'; end
312    server = FakeServer.new socket
313
314    @cache.servers = []
315    @cache.servers << server
316
317    e = assert_raise MemCache::MemCacheError do
318      @cache.get 'my_namespace:key'
319    end
320
321    assert_equal 'some io error', e.message
322  end
323
324  def test_get_cache_get_SystemCallError
325    socket = Object.new
326    def socket.write(arg) raise SystemCallError, 'some syscall error'; end
327    server = FakeServer.new socket
328
329    @cache.servers = []
330    @cache.servers << server
331
332    e = assert_raise MemCache::MemCacheError do
333      @cache.get 'my_namespace:key'
334    end
335
336    assert_equal 'unknown error - some syscall error', e.message
337  end
338
339  def test_get_no_connection
340    @cache.servers = 'localhost:1'
341    e = assert_raise MemCache::MemCacheError do
342      @cache.get 'key'
343    end
344
345    assert_match /^No connection to server/, e.message
346  end
347
348  def test_get_no_servers
349    @cache.servers = []
350    e = assert_raise MemCache::MemCacheError do
351      @cache.get 'key'
352    end
353
354    assert_equal 'No active servers', e.message
355  end
356
357  def test_get_multi
358    server = FakeServer.new
359    server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
360    server.socket.data.write "\004\b\"\0170123456789\r\n"
361    server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
362    server.socket.data.write "\004\b\"\0179876543210\r\n"
363    server.socket.data.write "END\r\n"
364    server.socket.data.rewind
365
366    @cache.servers = []
367    @cache.servers << server
368
369    values = @cache.get_multi 'key', 'keyb'
370
371    assert_equal "get my_namespace:key my_namespace:keyb\r\n",
372                 server.socket.written.string
373
374    expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
375
376    assert_equal expected.sort, values.sort
377  end
378
379  def test_get_raw
380    server = FakeServer.new
381    server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
382    server.socket.data.write "0123456789\r\n"
383    server.socket.data.write "END\r\n"
384    server.socket.data.rewind
385
386    @cache.servers = []
387    @cache.servers << server
388
389
390    value = @cache.get 'key', true
391
392    assert_equal "get my_namespace:key\r\n",
393                 @cache.servers.first.socket.written.string
394
395    assert_equal '0123456789', value
396  end
397
398  def test_get_server_for_key
399    server = @cache.get_server_for_key 'key'
400    assert_equal 'localhost', server.host
401    assert_equal 1, server.port
402  end
403
404  def test_get_server_for_key_multiple
405    s1 = util_setup_server @cache, 'one.example.com', ''
406    s2 = util_setup_server @cache, 'two.example.com', ''
407    @cache.instance_variable_set :@servers, [s1, s2]
408    @cache.instance_variable_set :@buckets, [s1, s2]
409
410    server = @cache.get_server_for_key 'keya'
411    assert_equal 'two.example.com', server.host
412    server = @cache.get_server_for_key 'keyb'
413    assert_equal 'one.example.com', server.host
414  end
415
416  def test_get_server_for_key_no_servers
417    @cache.servers = []
418
419    e = assert_raise MemCache::MemCacheError do
420      @cache.get_server_for_key 'key'
421    end
422
423    assert_equal 'No servers available', e.message
424  end
425
426  def test_get_server_for_key_spaces
427    e = assert_raise ArgumentError do
428      @cache.get_server_for_key 'space key'
429    end
430    assert_equal 'illegal character in key "space key"', e.message
431  end
432
433  def test_get_server_for_key_length
434    @cache.get_server_for_key 'x' * 250
435    long_key = 'x' * 251
436    e = assert_raise ArgumentError do
437      @cache.get_server_for_key long_key
438    end
439    assert_equal "key too long #{long_key.inspect}", e.message
440  end
441
442  def test_incr
443    server = FakeServer.new
444    server.socket.data.write "5\r\n"
445    server.socket.data.rewind
446
447    @cache.servers = []
448    @cache.servers << server
449
450    value = @cache.incr 'key'
451
452    assert_equal "incr my_namespace:key 1\r\n",
453                 @cache.servers.first.socket.written.string
454
455    assert_equal 5, value
456  end
457
458  def test_incr_not_found
459    server = FakeServer.new
460    server.socket.data.write "NOT_FOUND\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 nil, value
472  end
473
474  def test_incr_space_padding
475    server = FakeServer.new
476    server.socket.data.write "5 \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 5, value
488  end
489
490  def test_make_cache_key
491    assert_equal 'my_namespace:key', @cache.make_cache_key('key')
492    @cache.namespace = nil
493    assert_equal 'key', @cache.make_cache_key('key')
494  end
495
496  def test_servers
497    server = FakeServer.new
498    @cache.servers = []
499    @cache.servers << server
500    assert_equal [server], @cache.servers
501  end
502
503  def test_servers_equals_type_error
504    e = assert_raise TypeError do
505      @cache.servers = [Object.new]
506    end
507
508    assert_equal 'cannot convert Object into MemCache::Server', e.message
509  end
510
511  def test_set
512    server = FakeServer.new
513    server.socket.data.write "STORED\r\n"
514    server.socket.data.rewind
515    @cache.servers = []
516    @cache.servers << server
517
518    @cache.set 'key', 'value'
519
520    expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
521    assert_equal expected, server.socket.written.string
522  end
523
524  def test_set_expiry
525    server = FakeServer.new
526    server.socket.data.write "STORED\r\n"
527    server.socket.data.rewind
528    @cache.servers = []
529    @cache.servers << server
530
531    @cache.set 'key', 'value', 5
532
533    expected = "set my_namespace:key 0 5 9\r\n\004\b\"\nvalue\r\n"
534    assert_equal expected, server.socket.written.string
535  end
536
537  def test_set_raw
538    server = FakeServer.new
539    server.socket.data.write "STORED\r\n"
540    server.socket.data.rewind
541    @cache.servers = []
542    @cache.servers << server
543
544    @cache.set 'key', 'value', 0, true
545
546    expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
547    assert_equal expected, server.socket.written.string
548  end
549
550  def test_set_readonly
551    cache = MemCache.new :readonly => true
552
553    e = assert_raise MemCache::MemCacheError do
554      cache.set 'key', 'value'
555    end
556
557    assert_equal 'Update of readonly cache', e.message
558  end
559
560  def test_set_too_big
561    server = FakeServer.new
562    server.socket.data.write "SERVER_ERROR object too large for cache\r\n"
563    server.socket.data.rewind
564    @cache.servers = []
565    @cache.servers << server
566
567    e = assert_raise MemCache::MemCacheError do
568      @cache.set 'key', 'v'
569    end
570
571    assert_equal 'object too large for cache', e.message
572  end
573
574  def test_add
575    server = FakeServer.new
576    server.socket.data.write "STORED\r\n"
577    server.socket.data.rewind
578    @cache.servers = []
579    @cache.servers << server
580
581    @cache.add 'key', 'value'
582
583    expected = "add my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
584    assert_equal expected, server.socket.written.string
585  end
586
587  def test_add_exists
588    server = FakeServer.new
589    server.socket.data.write "NOT_STORED\r\n"
590    server.socket.data.rewind
591    @cache.servers = []
592    @cache.servers << server
593
594    @cache.add 'key', 'value'
595
596    expected = "add my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
597    assert_equal expected, server.socket.written.string
598  end
599
600  def test_add_expiry
601    server = FakeServer.new
602    server.socket.data.write "STORED\r\n"
603    server.socket.data.rewind
604    @cache.servers = []
605    @cache.servers << server
606
607    @cache.add 'key', 'value', 5
608
609    expected = "add my_namespace:key 0 5 9\r\n\004\b\"\nvalue\r\n"
610    assert_equal expected, server.socket.written.string
611  end
612
613  def test_add_raw
614    server = FakeServer.new
615    server.socket.data.write "STORED\r\n"
616    server.socket.data.rewind
617    @cache.servers = []
618    @cache.servers << server
619
620    @cache.add 'key', 'value', 0, true
621
622    expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
623    assert_equal expected, server.socket.written.string
624  end
625
626  def test_add_readonly
627    cache = MemCache.new :readonly => true
628
629    e = assert_raise MemCache::MemCacheError do
630      cache.add 'key', 'value'
631    end
632
633    assert_equal 'Update of readonly cache', e.message
634  end
635
636  def test_delete
637    server = FakeServer.new
638    @cache.servers = []
639    @cache.servers << server
640    
641    @cache.delete 'key'
642    
643    expected = "delete my_namespace:key 0\r\n"
644    assert_equal expected, server.socket.written.string
645  end
646
647  def test_delete_with_expiry
648    server = FakeServer.new
649    @cache.servers = []
650    @cache.servers << server
651    
652    @cache.delete 'key', 300
653    
654    expected = "delete my_namespace:key 300\r\n"
655    assert_equal expected, server.socket.written.string
656  end
657
658  def test_flush_all
659    @cache.servers = []
660    3.times { @cache.servers << FakeServer.new }
661
662    @cache.flush_all
663
664    expected = "flush_all\r\n"
665    @cache.servers.each do |server|
666      assert_equal expected, server.socket.written.string
667    end
668  end
669
670  def test_flush_all_failure
671    socket = FakeSocket.new
672    socket.data.write "ERROR\r\n"
673    socket.data.rewind
674    server = FakeServer.new socket
675    def server.host() "localhost"; end
676    def server.port() 11211; end
677
678    @cache.servers = []
679    @cache.servers << server
680
681    assert_raise MemCache::MemCacheError do
682      @cache.flush_all
683    end
684
685    assert_equal "flush_all\r\n", socket.written.string
686  end
687
688  def test_stats
689    socket = FakeSocket.new
690    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"
691    socket.data.rewind
692    server = FakeServer.new socket
693    def server.host() 'localhost'; end
694    def server.port() 11211; end
695
696    @cache.servers = []
697    @cache.servers << server
698
699    expected = {
700      'localhost:11211' => {
701        'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
702        'rusage_user' => 1.0003, 'dummy' => 'ok'
703      }
704    }
705    assert_equal expected, @cache.stats
706
707    assert_equal "stats\r\n", socket.written.string
708  end
709
710  def test_basic_threaded_operations_should_work
711    cache = MemCache.new :multithread => true,
712                         :namespace => 'my_namespace',
713                         :readonly => false
714    server = util_setup_server cache, 'example.com', "OK\r\n"
715    cache.instance_variable_set :@servers, [server]
716
717    assert_nothing_raised do
718      cache.set "test", "test value"
719    end
720  end
721
722  def test_basic_unthreaded_operations_should_work
723    cache = MemCache.new :multithread => false,
724                         :namespace => 'my_namespace',
725                         :readonly => false
726    server = util_setup_server cache, 'example.com', "OK\r\n"
727    cache.instance_variable_set :@servers, [server]
728
729    assert_nothing_raised do
730      cache.set "test", "test value"
731    end
732  end
733
734  def util_setup_fake_server
735    server = FakeServer.new
736    server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
737    server.socket.data.write "\004\b\"\0170123456789\r\n"
738    server.socket.data.write "END\r\n"
739    server.socket.data.rewind
740
741    @cache.servers = []
742    @cache.servers << server
743
744    return server
745  end
746
747  def util_setup_server(memcache, host, responses)
748    server = MemCache::Server.new memcache, host
749    server.instance_variable_set :@sock, StringIO.new(responses)
750
751    @cache.servers = []
752    @cache.servers << server
753
754    return server
755  end
756
757end
758