PageRenderTime 160ms CodeModel.GetById 2ms app.highlight 150ms RepoModel.GetById 1ms app.codeStats 0ms

/test/test_mem_cache.rb

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