PageRenderTime 7ms CodeModel.GetById 5ms app.highlight 161ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/bundle/ruby/1.8/gems/memcache-client-1.7.6/test/test_mem_cache.rb

https://github.com/alecslupu/Free-RPG-Engine-FaceBook-Game-App
Ruby | 1220 lines | 933 code | 271 blank | 16 comment | 7 complexity | 19966e5d4d66d16919047694af8a3719 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
  13Thread.abort_on_exception = true
  14$TESTING = true
  15
  16require File.dirname(__FILE__) + '/../lib/memcache' if not defined?(MemCache)
  17
  18class MemCache
  19
  20  attr_writer :namespace
  21  attr_writer :autofix_keys
  22  
  23end
  24
  25class 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
  46end
  47
  48class 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  
  80end
  81
  82class 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
 112end
 113
 114class 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
 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_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 "END\r\n"
 606    server.socket.data.rewind
 607
 608    @cache.servers = []
 609    @cache.servers << server
 610
 611
 612    value = @cache.get 'key', true
 613
 614    assert_equal "get my_namespace:key\r\n",
 615                 @cache.servers.first.socket.written.string
 616
 617    assert_equal '0123456789', value
 618  end
 619
 620  def test_get_server_for_key
 621    server = @cache.get_server_for_key 'key'
 622    assert_equal 'localhost', server.host
 623    assert_equal 1, server.port
 624  end
 625
 626  def test_get_server_for_key_multiple
 627    s1 = util_setup_server @cache, 'one.example.com', ''
 628    s2 = util_setup_server @cache, 'two.example.com', ''
 629    @cache.servers = [s1, s2]
 630
 631    server = @cache.get_server_for_key 'keya'
 632    assert_equal 'two.example.com', server.host
 633    server = @cache.get_server_for_key 'keyb'
 634    assert_equal 'two.example.com', server.host
 635    server = @cache.get_server_for_key 'keyc'
 636    assert_equal 'two.example.com', server.host
 637    server = @cache.get_server_for_key 'keyd'
 638    assert_equal 'one.example.com', server.host
 639  end
 640
 641  def test_get_server_for_key_no_servers
 642    @cache.servers = []
 643
 644    e = assert_raise MemCache::MemCacheError do
 645      @cache.get_server_for_key 'key'
 646    end
 647
 648    assert_equal 'No servers available', e.message
 649  end
 650
 651  def test_get_server_for_key_spaces
 652    e = assert_raise ArgumentError do
 653      @cache.get_server_for_key 'space key'
 654    end
 655    assert_equal 'illegal character in key "space key"', e.message
 656  end
 657
 658  def test_get_server_for_key_length
 659    @cache.get_server_for_key 'x' * 250
 660    long_key = 'x' * 251
 661    e = assert_raise ArgumentError do
 662      @cache.get_server_for_key long_key
 663    end
 664    assert_equal "key too long #{long_key.inspect}", e.message
 665  end
 666
 667  def test_incr
 668    server = FakeServer.new
 669    server.socket.data.write "5\r\n"
 670    server.socket.data.rewind
 671
 672    @cache.servers = []
 673    @cache.servers << server
 674
 675    value = @cache.incr 'key'
 676
 677    assert_equal "incr my_namespace:key 1\r\n",
 678                 @cache.servers.first.socket.written.string
 679
 680    assert_equal 5, value
 681  end
 682
 683  def test_incr_not_found
 684    server = FakeServer.new
 685    server.socket.data.write "NOT_FOUND\r\n"
 686    server.socket.data.rewind
 687
 688    @cache.servers = []
 689    @cache.servers << server
 690
 691    value = @cache.incr 'key'
 692
 693    assert_equal "incr my_namespace:key 1\r\n",
 694                 @cache.servers.first.socket.written.string
 695
 696    assert_equal nil, value
 697  end
 698
 699  def test_incr_space_padding
 700    server = FakeServer.new
 701    server.socket.data.write "5 \r\n"
 702    server.socket.data.rewind
 703
 704    @cache.servers = []
 705    @cache.servers << server
 706
 707    value = @cache.incr 'key'
 708
 709    assert_equal "incr my_namespace:key 1\r\n",
 710                 @cache.servers.first.socket.written.string
 711
 712    assert_equal 5, value
 713  end
 714
 715  def test_make_cache_key
 716    assert_equal 'my_namespace:key', @cache.make_cache_key('key')
 717    @cache.namespace = nil
 718    assert_equal 'key', @cache.make_cache_key('key')
 719  end
 720
 721  def test_make_cache_key_without_autofix
 722    @cache.autofix_keys = false
 723
 724    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"
 725    hash = Digest::SHA1.hexdigest(key)
 726    @cache.namespace = nil
 727    assert_equal key, @cache.make_cache_key(key)
 728
 729    @cache.autofix_keys = true
 730
 731    @cache.namespace = "my_namespace"
 732    assert_equal 'my_namespace:key', @cache.make_cache_key('key')
 733    @cache.namespace = nil
 734    assert_equal 'key', @cache.make_cache_key('key')
 735    
 736    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"
 737    hash = Digest::SHA1.hexdigest(key)
 738    @cache.namespace = "my_namespace"
 739    assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
 740    @cache.namespace = nil
 741    assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
 742    
 743    key = "a short key with spaces"
 744    hash = Digest::SHA1.hexdigest(key)
 745    @cache.namespace = "my_namespace"
 746    assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
 747    @cache.namespace = nil
 748    assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
 749  end
 750  
 751  def test_servers
 752    server = FakeServer.new
 753    @cache.servers = []
 754    @cache.servers << server
 755    assert_equal [server], @cache.servers
 756  end
 757
 758  def test_set
 759    server = FakeServer.new
 760    server.socket.data.write "STORED\r\n"
 761    server.socket.data.rewind
 762    @cache.servers = []
 763    @cache.servers << server
 764
 765    @cache.set 'key', 'value'
 766
 767    dumped = Marshal.dump('value')
 768    expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
 769#    expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
 770    assert_equal expected, server.socket.written.string
 771  end
 772
 773  def test_set_expiry
 774    server = FakeServer.new
 775    server.socket.data.write "STORED\r\n"
 776    server.socket.data.rewind
 777    @cache.servers = []
 778    @cache.servers << server
 779
 780    @cache.set 'key', 'value', 5
 781
 782    dumped = Marshal.dump('value')
 783    expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
 784    assert_equal expected, server.socket.written.string
 785  end
 786
 787  def test_set_raw
 788    server = FakeServer.new
 789    server.socket.data.write "STORED\r\n"
 790    server.socket.data.rewind
 791    @cache.servers = []
 792    @cache.servers << server
 793
 794    @cache.set 'key', 'value', 0, true
 795
 796    expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
 797    assert_equal expected, server.socket.written.string
 798  end
 799
 800  def test_set_readonly
 801    cache = MemCache.new :readonly => true
 802
 803    e = assert_raise MemCache::MemCacheError do
 804      cache.set 'key', 'value'
 805    end
 806
 807    assert_equal 'Update of readonly cache', e.message
 808  end
 809
 810  def test_check_size_on
 811    cache = MemCache.new :check_size => true
 812
 813    server = FakeServer.new
 814    server.socket.data.write "STORED\r\n"
 815    server.socket.data.rewind
 816
 817    cache.servers = []
 818    cache.servers << server
 819
 820    e = assert_raise MemCache::MemCacheError do
 821      cache.set 'key', 'v' * 1048577
 822    end
 823
 824    assert_equal 'Value too large, memcached can only store 1MB of data per key', e.message
 825  end
 826
 827  def test_check_size_off
 828    cache = MemCache.new :check_size => false
 829
 830    server = FakeServer.new
 831    server.socket.data.write "STORED\r\n"
 832    server.socket.data.rewind
 833
 834    cache.servers = []
 835    cache.servers << server
 836
 837    assert_nothing_raised do
 838      cache.set 'key', 'v' * 1048577
 839    end
 840  end
 841
 842  def test_set_too_big
 843    server = FakeServer.new
 844
 845    # Write two messages to the socket to test failover
 846    server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
 847    server.socket.data.rewind
 848
 849    @cache.servers = []
 850    @cache.servers << server
 851
 852    e = assert_raise MemCache::MemCacheError do
 853      @cache.set 'key', 'v'
 854    end
 855
 856    assert_match(/object too large for cache/, e.message)
 857  end
 858
 859  def test_prepend
 860    server = FakeServer.new
 861    server.socket.data.write "STORED\r\n"
 862    server.socket.data.rewind
 863    @cache.servers = []
 864    @cache.servers << server
 865
 866    @cache.prepend 'key', 'value'
 867    
 868    dumped = Marshal.dump('value')
 869
 870    expected = "prepend my_namespace:key 0 0 5\r\nvalue\r\n"
 871    assert_equal expected, server.socket.written.string
 872  end
 873
 874  def test_append
 875    server = FakeServer.new
 876    server.socket.data.write "STORED\r\n"
 877    server.socket.data.rewind
 878    @cache.servers = []
 879    @cache.servers << server
 880
 881    @cache.append 'key', 'value'
 882    
 883    expected = "append my_namespace:key 0 0 5\r\nvalue\r\n"
 884    assert_equal expected, server.socket.written.string
 885  end
 886
 887  def test_replace
 888    server = FakeServer.new
 889    server.socket.data.write "STORED\r\n"
 890    server.socket.data.rewind
 891    @cache.servers = []
 892    @cache.servers << server
 893
 894    @cache.replace 'key', 'value', 150
 895    
 896    dumped = Marshal.dump('value')
 897
 898    expected = "replace my_namespace:key 0 150 #{dumped.length}\r\n#{dumped}\r\n"
 899    assert_equal expected, server.socket.written.string
 900  end
 901
 902  def test_add
 903    server = FakeServer.new
 904    server.socket.data.write "STORED\r\n"
 905    server.socket.data.rewind
 906    @cache.servers = []
 907    @cache.servers << server
 908
 909    @cache.add 'key', 'value'
 910    
 911    dumped = Marshal.dump('value')
 912
 913    expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
 914    assert_equal expected, server.socket.written.string
 915  end
 916
 917  def test_add_exists
 918    server = FakeServer.new
 919    server.socket.data.write "NOT_STORED\r\n"
 920    server.socket.data.rewind
 921    @cache.servers = []
 922    @cache.servers << server
 923
 924    @cache.add 'key', 'value'
 925
 926    dumped = Marshal.dump('value')
 927    expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
 928    assert_equal expected, server.socket.written.string
 929  end
 930
 931  def test_add_expiry
 932    server = FakeServer.new
 933    server.socket.data.write "STORED\r\n"
 934    server.socket.data.rewind
 935    @cache.servers = []
 936    @cache.servers << server
 937
 938    @cache.add 'key', 'value', 5
 939
 940    dumped = Marshal.dump('value')
 941    expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
 942    assert_equal expected, server.socket.written.string
 943  end
 944
 945  def test_add_raw
 946    server = FakeServer.new
 947    server.socket.data.write "STORED\r\n"
 948    server.socket.data.rewind
 949    @cache.servers = []
 950    @cache.servers << server
 951
 952    @cache.add 'key', 'value', 0, true
 953
 954    expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
 955    assert_equal expected, server.socket.written.string
 956  end
 957
 958  def test_add_raw_int
 959    server = FakeServer.new
 960    server.socket.data.write "STORED\r\n"
 961    server.socket.data.rewind
 962    @cache.servers = []
 963    @cache.servers << server
 964
 965    @cache.add 'key', 12, 0, true
 966
 967    expected = "add my_namespace:key 0 0 2\r\n12\r\n"
 968    assert_equal expected, server.socket.written.string
 969  end
 970
 971  def test_add_readonly
 972    cache = MemCache.new :readonly => true
 973
 974    e = assert_raise MemCache::MemCacheError do
 975      cache.add 'key', 'value'
 976    end
 977
 978    assert_equal 'Update of readonly cache', e.message
 979  end
 980
 981  def test_delete
 982    server = FakeServer.new
 983    @cache.servers = []
 984    @cache.servers << server
 985    
 986    @cache.delete 'key'
 987    
 988    expected = "delete my_namespace:key 0\r\n"
 989    assert_equal expected, server.socket.written.string
 990  end
 991
 992  def test_delete_with_expiry
 993    server = FakeServer.new
 994    @cache.servers = []
 995    @cache.servers << server
 996    
 997    @cache.delete 'key', 300
 998    
 999    expected = "delete my_namespace:key 300\r\n"
1000    assert_equal expected, server.socket.written.string
1001  end
1002
1003  def test_flush_all
1004    @cache.servers = []
1005    3.times { @cache.servers << FakeServer.new }
1006
1007    @cache.flush_all
1008
1009    expected = "flush_all\r\n"
1010    @cache.servers.each do |server|
1011      assert_equal expected, server.socket.written.string
1012    end
1013  end
1014
1015  def test_flush_all_with_delay
1016    @cache.servers = []
1017    3.times { @cache.servers << FakeServer.new }
1018
1019    @cache.flush_all(10)
1020
1021    @cache.servers.each_with_index do |server, idx|
1022      expected = "flush_all #{idx*10}\r\n"
1023      assert_equal expected, server.socket.written.string
1024    end
1025  end
1026
1027  def test_flush_all_failure
1028    socket = FakeSocket.new
1029
1030    # Write two messages to the socket to test failover
1031    socket.data.write "ERROR\r\nERROR\r\n"
1032    socket.data.rewind
1033
1034    server = FakeServer.new socket
1035
1036    @cache.servers = []
1037    @cache.servers << server
1038
1039    assert_raise MemCache::MemCacheError do
1040      @cache.flush_all
1041    end
1042
1043    assert_match(/flush_all\r\n/, socket.written.string)
1044  end
1045  
1046  def test_flush_all_for_real
1047    requirement(memcached_running?, 'A real memcached server must be running for testing flush_all') do
1048      cache = MemCache.new "localhost:11211", :namespace => "test_flush_all"
1049      k, v = "1234", "test"
1050      assert_nil cache.get(k)
1051      cache.set(k, v)
1052      assert_equal v, cache.get(k)
1053      cache.flush_all
1054      assert_nil cache.get(k)
1055    end
1056  end
1057
1058  def test_stats
1059    socket = FakeSocket.new
1060    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"
1061    socket.data.rewind
1062    server = FakeServer.new socket
1063    def server.host() 'localhost'; end
1064    def server.port() 11211; end
1065
1066    @cache.servers = []
1067    @cache.servers << server
1068
1069    expected = {
1070      'localhost:11211' => {
1071        'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
1072        'rusage_user' => 1.0003, 'dummy' => 'ok'
1073      }
1074    }
1075    assert_equal expected, @cache.stats
1076
1077    assert_equal "stats\r\n", socket.written.string
1078  end
1079
1080  def test_basic_threaded_operations_should_work
1081    cache = MemCache.new :multithread => true,
1082                         :namespace => 'my_namespace',
1083                         :readonly => false
1084
1085    server = FakeServer.new
1086    server.socket.data.write "STORED\r\n"
1087    server.socket.data.rewind
1088
1089    cache.servers = []
1090    cache.servers << server
1091
1092    assert cache.multithread
1093
1094    assert_nothing_raised do
1095      cache.set "test", "test value"
1096    end
1097
1098    output = server.socket.written.string
1099    assert_match(/set my_namespace:test/, output)
1100    assert_match(/test value/, output)
1101  end
1102
1103  def test_namespace_separator
1104    cache = MemCache.new :namespace => 'ns', :namespace_separator => ''
1105
1106    server = FakeServer.new
1107    server.socket.data.write "STORED\r\n"
1108    server.socket.data.rewind
1109
1110    cache.servers = []
1111    cache.servers << server
1112
1113    assert_nothing_raised do
1114      cache.set "test", "test value"
1115    end
1116
1117    output = server.socket.written.string
1118    assert_match(/set nstest/, output)
1119    assert_match(/test value/, output)
1120  end
1121
1122  def test_basic_unthreaded_operations_should_work
1123    cache = MemCache.new :multithread => false,
1124                         :namespace => 'my_namespace',
1125                         :readonly => false
1126
1127    server = FakeServer.new
1128    server.socket.data.write "STORED\r\n"
1129    server.socket.data.rewind
1130
1131    cache.servers = []
1132    cache.servers << server
1133
1134    assert !cache.multithread
1135
1136    assert_nothing_raised do
1137      cache.set "test", "test value"
1138    end
1139
1140    output = server.socket.written.string
1141    assert_match(/set my_namespace:test/, output)
1142    assert_match(/test value/, output)
1143  end
1144
1145  def util_setup_fake_server
1146    server = FakeServer.new
1147    server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
1148    server.socket.data.write "\004\b\"\0170123456789\r\n"
1149    server.socket.data.write "END\r\n"
1150    server.socket.data.rewind
1151
1152    @cache.servers = []
1153    @cache.servers << server
1154
1155    return server
1156  end
1157
1158  def util_setup_server(memcache, host, responses)
1159    server = MemCache::Server.new memcache, host
1160    server.instance_variable_set :@sock, StringIO.new(responses)
1161
1162    @cache.servers = []
1163    @cache.servers << server
1164
1165    return server
1166  end
1167
1168  def test_crazy_multithreaded_access
1169    requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
1170
1171      # Use a null logger to verify logging doesn't blow up at runtime
1172      cache = MemCache.new(['localhost:11211', '127.0.0.1:11211'], :logger => Logger.new('/dev/null'))
1173      cache.flush_all
1174      workers = []
1175
1176      cache.set('f', 'zzz')
1177      assert_equal "STORED\r\n", (cache.cas('f') do |value|
1178        value << 'z'
1179      end)
1180      assert_equal 'zzzz', cache.get('f')
1181
1182      # Have a bunch of threads perform a bunch of operations at the same time.
1183      # Verify the result of each operation to ensure the request and response
1184      # are not intermingled between threads.
1185      10.times do
1186        workers << Thread.new do
1187          100.times do
1188            cache.set('a', 9)
1189            cache.set('b', 11)
1190            cache.add('c', 10, 0, true)
1191            cache.set('d', 'a', 100, true)
1192            cache.set('e', 'x', 100, true)
1193            cache.set('f', 'zzz')
1194            assert_not_nil(cache.cas('f') do |value|
1195              value << 'z'
1196            end)
1197            cache.append('d', 'b')
1198            cache.prepend('e', 'y')
1199            assert_equal "NOT_STORED\r\n", cache.add('a', 11)
1200            assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
1201            inc = cache.incr('c', 10)
1202            assert_equal 0, inc % 5
1203            assert inc > 14
1204            assert cache.decr('c', 5) > 14
1205            assert_equal 11, cache.get('b')
1206            d = cache.get('d', true)
1207            assert_match(/\Aab*\Z/, d)
1208            e = cache.get('e', true)
1209            assert_match(/\Ay*x\Z/, e)
1210          end
1211        end
1212      end
1213
1214      workers.each { |w| w.join }
1215      cache.flush_all
1216    end
1217  end
1218
1219end
1220