PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/test/test_mem_cache.rb

https://github.com/jsl/memcache-client
Ruby | 1170 lines | 891 code | 263 blank | 16 comment | 6 complexity | 0385f2389b137ee6c3489b3cb90aaa60 MD5 | raw file
  1. # encoding: utf-8
  2. require 'logger'
  3. require 'stringio'
  4. require 'test/unit'
  5. require 'rubygems'
  6. begin
  7. gem 'flexmock'
  8. require 'flexmock/test_unit'
  9. rescue LoadError => e
  10. puts "Some tests require flexmock, please run `gem install flexmock`"
  11. end
  12. Thread.abort_on_exception = true
  13. $TESTING = true
  14. require File.dirname(__FILE__) + '/../lib/memcache' if not defined?(MemCache)
  15. class MemCache
  16. attr_writer :namespace
  17. end
  18. class FakeSocket
  19. attr_reader :written, :data
  20. def initialize
  21. @written = StringIO.new
  22. @data = StringIO.new
  23. end
  24. def write(data)
  25. @written.write data
  26. end
  27. def gets
  28. @data.gets
  29. end
  30. def read(arg)
  31. @data.read arg
  32. end
  33. end
  34. class Test::Unit::TestCase
  35. def requirement(bool, msg)
  36. if bool
  37. yield
  38. else
  39. puts msg
  40. assert true
  41. end
  42. end
  43. def memcached_running?
  44. TCPSocket.new('localhost', 11211) rescue false
  45. end
  46. def xprofile(name, &block)
  47. a = Time.now
  48. block.call
  49. Time.now - a
  50. end
  51. def profile(name, &block)
  52. require 'ruby-prof'
  53. a = Time.now
  54. result = RubyProf.profile(&block)
  55. time = Time.now - a
  56. printer = RubyProf::GraphHtmlPrinter.new(result)
  57. File.open("#{name}.html", 'w') do |f|
  58. printer.print(f, :min_percent=>1)
  59. end
  60. time
  61. end
  62. end
  63. class FakeServer
  64. attr_accessor :host, :port, :socket, :weight, :multithread, :status
  65. def initialize(socket = nil)
  66. @closed = false
  67. @host = 'example.com'
  68. @port = 11211
  69. @socket = socket || FakeSocket.new
  70. @weight = 1
  71. @multithread = true
  72. @status = "CONNECTED"
  73. end
  74. def close
  75. # begin
  76. # raise "Already closed"
  77. # rescue => e
  78. # puts e.backtrace.join("\n")
  79. # end
  80. @closed = true
  81. @socket = nil
  82. @status = "NOT CONNECTED"
  83. end
  84. def alive?
  85. # puts "I'm #{@closed ? 'dead' : 'alive'}"
  86. !@closed
  87. end
  88. end
  89. class TestMemCache < Test::Unit::TestCase
  90. def setup
  91. @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
  92. end
  93. def test_performance
  94. requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
  95. cache = MemCache.new(['localhost:11211',"127.0.0.1:11211"])
  96. cache.flush_all
  97. cache.add('a', 1, 120)
  98. with = xprofile 'get' do
  99. 1000.times do
  100. cache.get('a')
  101. end
  102. end
  103. puts ''
  104. puts "1000 gets with socket timeout: #{with} sec"
  105. cache = MemCache.new(['localhost:11211',"127.0.0.1:11211"], :timeout => nil)
  106. cache.add('a', 1, 120)
  107. without = xprofile 'get' do
  108. 1000.times do
  109. cache.get('a')
  110. end
  111. end
  112. puts "1000 gets without socket timeout: #{without} sec"
  113. end
  114. end
  115. def test_consistent_hashing
  116. requirement(self.respond_to?(:flexmock), 'Flexmock is required to run this test') do
  117. flexmock(MemCache::Server).new_instances.should_receive(:alive?).and_return(true)
  118. # Setup a continuum of two servers
  119. @cache.servers = ['mike1', 'mike2', 'mike3']
  120. keys = []
  121. 1000.times do |idx|
  122. keys << idx.to_s
  123. end
  124. before_continuum = keys.map {|key| @cache.get_server_for_key(key) }
  125. @cache.servers = ['mike1', 'mike2', 'mike3', 'mike4']
  126. after_continuum = keys.map {|key| @cache.get_server_for_key(key) }
  127. same_count = before_continuum.zip(after_continuum).find_all {|a| a[0].host == a[1].host }.size
  128. # With continuum, we should see about 75% of the keys map to the same server
  129. # With modulo, we would see about 25%.
  130. assert same_count > 700
  131. end
  132. end
  133. def test_get_multi_with_server_failure
  134. @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace', :logger => nil #Logger.new(STDOUT)
  135. s1 = FakeServer.new
  136. s2 = FakeServer.new
  137. # Write two messages to the socket to test failover
  138. s1.socket.data.write "VALUE my_namespace:a 0 14\r\n\004\b\"\0170123456789\r\nEND\r\n"
  139. s1.socket.data.rewind
  140. s2.socket.data.write "bogus response\r\nbogus response\r\n"
  141. s2.socket.data.rewind
  142. @cache.servers = [s1, s2]
  143. assert s1.alive?
  144. assert s2.alive?
  145. # a maps to s1, the rest map to s2
  146. value = @cache.get_multi(['foo', 'bar', 'a', 'b', 'c'])
  147. assert_equal({'a'=>'0123456789'}, value)
  148. assert s1.alive?
  149. assert !s2.alive?
  150. end
  151. def test_cache_get_with_failover
  152. @cache = MemCache.new 'localhost:1', :namespace => 'my_namespace', :logger => nil#Logger.new(STDOUT)
  153. s1 = FakeServer.new
  154. s2 = FakeServer.new
  155. # Write two messages to the socket to test failover
  156. s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
  157. s1.socket.data.rewind
  158. s2.socket.data.write "bogus response\r\nbogus response\r\n"
  159. s2.socket.data.rewind
  160. @cache.instance_variable_set(:@failover, true)
  161. @cache.servers = [s1, s2]
  162. assert s1.alive?
  163. assert s2.alive?
  164. @cache.get('foo')
  165. assert s1.alive?
  166. assert !s2.alive?
  167. end
  168. def test_cache_get_without_failover
  169. s1 = FakeServer.new
  170. s2 = FakeServer.new
  171. s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
  172. s1.socket.data.rewind
  173. s2.socket.data.write "bogus response\r\nbogus response\r\n"
  174. s2.socket.data.rewind
  175. @cache.instance_variable_set(:@failover, false)
  176. @cache.servers = [s1, s2]
  177. assert s1.alive?
  178. assert s2.alive?
  179. e = assert_raise MemCache::MemCacheError do
  180. @cache.get('foo')
  181. end
  182. assert s1.alive?
  183. assert !s2.alive?
  184. assert_equal "No servers available", e.message
  185. end
  186. def test_cache_get
  187. server = util_setup_fake_server
  188. assert_equal "\004\b\"\0170123456789",
  189. @cache.cache_get(server, 'my_namespace:key')
  190. assert_equal "get my_namespace:key\r\n",
  191. server.socket.written.string
  192. end
  193. def test_cache_get_EOF
  194. server = util_setup_fake_server
  195. server.socket.data.string = ''
  196. e = assert_raise IndexError do
  197. @cache.cache_get server, 'my_namespace:key'
  198. end
  199. assert_equal "No connection to server (NOT CONNECTED)", e.message
  200. end
  201. def test_cache_get_bad_state
  202. server = FakeServer.new
  203. # Write two messages to the socket to test failover
  204. server.socket.data.write "bogus response\r\nbogus response\r\n"
  205. server.socket.data.rewind
  206. @cache.servers = []
  207. @cache.servers << server
  208. e = assert_raise IndexError do
  209. @cache.cache_get(server, 'my_namespace:key')
  210. end
  211. assert_match /#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message
  212. assert !server.alive?
  213. end
  214. def test_cache_get_miss
  215. socket = FakeSocket.new
  216. socket.data.write "END\r\n"
  217. socket.data.rewind
  218. server = FakeServer.new socket
  219. assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
  220. assert_equal "get my_namespace:key\r\n",
  221. socket.written.string
  222. end
  223. def test_cache_get_multi
  224. server = util_setup_fake_server
  225. server.socket.data.write "VALUE foo 0 7\r\n"
  226. server.socket.data.write "\004\b\"\bfoo\r\n"
  227. server.socket.data.write "VALUE bar 0 7\r\n"
  228. server.socket.data.write "\004\b\"\bbar\r\n"
  229. server.socket.data.write "END\r\n"
  230. server.socket.data.rewind
  231. result = @cache.cache_get_multi server, 'foo bar baz'
  232. assert_equal 2, result.length
  233. assert_equal "\004\b\"\bfoo", result['foo']
  234. assert_equal "\004\b\"\bbar", result['bar']
  235. end
  236. def test_cache_get_multi_EOF
  237. server = util_setup_fake_server
  238. server.socket.data.string = ''
  239. e = assert_raise IndexError do
  240. @cache.cache_get_multi server, 'my_namespace:key'
  241. end
  242. assert_equal "No connection to server (NOT CONNECTED)", e.message
  243. end
  244. def test_cache_get_multi_bad_state
  245. server = FakeServer.new
  246. # Write two messages to the socket to test failover
  247. server.socket.data.write "bogus response\r\nbogus response\r\n"
  248. server.socket.data.rewind
  249. @cache.servers = []
  250. @cache.servers << server
  251. e = assert_raise IndexError do
  252. @cache.cache_get_multi server, 'my_namespace:key'
  253. end
  254. assert_match /#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message
  255. assert !server.alive?
  256. end
  257. def test_multithread_error
  258. server = FakeServer.new
  259. server.multithread = false
  260. @cache = MemCache.new(['localhost:1'], :multithread => false)
  261. server.socket.data.write "bogus response\r\nbogus response\r\n"
  262. server.socket.data.rewind
  263. @cache.servers = []
  264. @cache.servers << server
  265. assert_nothing_raised do
  266. @cache.set 'a', 1
  267. end
  268. passed = true
  269. Thread.new do
  270. begin
  271. @cache.set 'b', 2
  272. passed = false
  273. rescue MemCache::MemCacheError => me
  274. passed = me.message =~ /multiple threads/
  275. end
  276. end
  277. assert passed
  278. end
  279. def test_initialize
  280. cache = MemCache.new :namespace => 'my_namespace', :readonly => true
  281. assert_equal 'my_namespace', cache.namespace
  282. assert_equal true, cache.readonly?
  283. assert_equal true, cache.servers.empty?
  284. end
  285. def test_initialize_compatible
  286. cache = MemCache.new ['localhost:11211', 'localhost:11212'],
  287. :namespace => 'my_namespace', :readonly => true
  288. assert_equal 'my_namespace', cache.namespace
  289. assert_equal true, cache.readonly?
  290. assert_equal false, cache.servers.empty?
  291. end
  292. def test_initialize_compatible_no_hash
  293. cache = MemCache.new ['localhost:11211', 'localhost:11212']
  294. assert_equal nil, cache.namespace
  295. assert_equal false, cache.readonly?
  296. assert_equal false, cache.servers.empty?
  297. end
  298. def test_initialize_compatible_one_server
  299. cache = MemCache.new 'localhost:11211'
  300. assert_equal nil, cache.namespace
  301. assert_equal false, cache.readonly?
  302. assert_equal false, cache.servers.empty?
  303. end
  304. def test_initialize_compatible_bad_arg
  305. e = assert_raise ArgumentError do
  306. cache = MemCache.new Object.new
  307. end
  308. assert_equal 'first argument must be Array, Hash or String', e.message
  309. end
  310. def test_initialize_multiple_servers
  311. cache = MemCache.new %w[localhost:11211 localhost:11212],
  312. :namespace => 'my_namespace', :readonly => true
  313. assert_equal 'my_namespace', cache.namespace
  314. assert_equal true, cache.readonly?
  315. assert_equal false, cache.servers.empty?
  316. assert !cache.instance_variable_get(:@continuum).empty?
  317. end
  318. def test_initialize_too_many_args
  319. assert_raises ArgumentError do
  320. MemCache.new 1, 2, 3
  321. end
  322. end
  323. def test_decr
  324. server = FakeServer.new
  325. server.socket.data.write "5\r\n"
  326. server.socket.data.rewind
  327. @cache.servers = []
  328. @cache.servers << server
  329. value = @cache.decr 'key'
  330. assert_equal "decr my_namespace:key 1\r\n",
  331. @cache.servers.first.socket.written.string
  332. assert_equal 5, value
  333. end
  334. def test_decr_not_found
  335. server = FakeServer.new
  336. server.socket.data.write "NOT_FOUND\r\n"
  337. server.socket.data.rewind
  338. @cache.servers = []
  339. @cache.servers << server
  340. value = @cache.decr 'key'
  341. assert_equal "decr my_namespace:key 1\r\n",
  342. @cache.servers.first.socket.written.string
  343. assert_equal nil, value
  344. end
  345. def test_decr_space_padding
  346. server = FakeServer.new
  347. server.socket.data.write "5 \r\n"
  348. server.socket.data.rewind
  349. @cache.servers = []
  350. @cache.servers << server
  351. value = @cache.decr 'key'
  352. assert_equal "decr my_namespace:key 1\r\n",
  353. @cache.servers.first.socket.written.string
  354. assert_equal 5, value
  355. end
  356. def test_get
  357. util_setup_fake_server
  358. value = @cache.get 'key'
  359. assert_equal "get my_namespace:key\r\n",
  360. @cache.servers.first.socket.written.string
  361. assert_equal '0123456789', value
  362. end
  363. def test_fetch_without_a_block
  364. server = FakeServer.new
  365. server.socket.data.write "END\r\n"
  366. server.socket.data.rewind
  367. @cache.servers = [server]
  368. flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
  369. value = @cache.fetch('key', 1)
  370. assert_equal nil, value
  371. end
  372. def test_fetch_miss
  373. server = FakeServer.new
  374. server.socket.data.write "END\r\n"
  375. server.socket.data.rewind
  376. @cache.servers = [server]
  377. flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
  378. flexmock(@cache).should_receive(:add).with('key', 'value', 1, false)
  379. value = @cache.fetch('key', 1) { 'value' }
  380. assert_equal 'value', value
  381. end
  382. def test_fetch_hit
  383. server = FakeServer.new
  384. server.socket.data.write "END\r\n"
  385. server.socket.data.rewind
  386. @cache.servers = [server]
  387. flexmock(@cache).should_receive(:get).with('key', false).and_return('value')
  388. flexmock(@cache).should_receive(:add).never
  389. value = @cache.fetch('key', 1) { raise 'Should not be called.' }
  390. assert_equal 'value', value
  391. end
  392. def test_get_bad_key
  393. util_setup_fake_server
  394. assert_raise ArgumentError do @cache.get 'k y' end
  395. util_setup_fake_server
  396. assert_raise ArgumentError do @cache.get 'k' * 250 end
  397. end
  398. def test_get_cache_get_IOError
  399. socket = Object.new
  400. def socket.write(arg) raise IOError, 'some io error'; end
  401. server = FakeServer.new socket
  402. @cache.servers = []
  403. @cache.servers << server
  404. e = assert_raise MemCache::MemCacheError do
  405. @cache.get 'my_namespace:key'
  406. end
  407. assert_equal 'some io error', e.message
  408. end
  409. def test_get_cache_get_SystemCallError
  410. socket = Object.new
  411. def socket.write(arg) raise SystemCallError, 'some syscall error'; end
  412. server = FakeServer.new socket
  413. @cache.servers = []
  414. @cache.servers << server
  415. e = assert_raise MemCache::MemCacheError do
  416. @cache.get 'my_namespace:key'
  417. end
  418. assert_equal 'unknown error - some syscall error', e.message
  419. end
  420. def test_get_no_connection
  421. @cache.servers = 'localhost:1'
  422. e = assert_raise MemCache::MemCacheError do
  423. @cache.get 'key'
  424. end
  425. assert_match /^No connection to server/, e.message
  426. end
  427. def test_get_no_servers
  428. @cache.servers = []
  429. e = assert_raise MemCache::MemCacheError do
  430. @cache.get 'key'
  431. end
  432. assert_equal 'No active servers', e.message
  433. end
  434. def test_get_multi
  435. server = FakeServer.new
  436. server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
  437. server.socket.data.write "\004\b\"\0170123456789\r\n"
  438. server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
  439. server.socket.data.write "\004\b\"\0179876543210\r\n"
  440. server.socket.data.write "END\r\n"
  441. server.socket.data.rewind
  442. @cache.servers = []
  443. @cache.servers << server
  444. values = @cache.get_multi 'key', 'keyb'
  445. assert_equal "get my_namespace:key my_namespace:keyb\r\n",
  446. server.socket.written.string
  447. expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
  448. assert_equal expected.sort, values.sort
  449. end
  450. def test_get_raw
  451. server = FakeServer.new
  452. server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
  453. server.socket.data.write "0123456789\r\n"
  454. server.socket.data.write "END\r\n"
  455. server.socket.data.rewind
  456. @cache.servers = []
  457. @cache.servers << server
  458. value = @cache.get 'key', true
  459. assert_equal "get my_namespace:key\r\n",
  460. @cache.servers.first.socket.written.string
  461. assert_equal '0123456789', value
  462. end
  463. def test_get_server_for_key
  464. server = @cache.get_server_for_key 'key'
  465. assert_equal 'localhost', server.host
  466. assert_equal 1, server.port
  467. end
  468. def test_get_server_for_key_multiple
  469. s1 = util_setup_server @cache, 'one.example.com', ''
  470. s2 = util_setup_server @cache, 'two.example.com', ''
  471. @cache.servers = [s1, s2]
  472. server = @cache.get_server_for_key 'keya'
  473. assert_equal 'two.example.com', server.host
  474. server = @cache.get_server_for_key 'keyb'
  475. assert_equal 'two.example.com', server.host
  476. server = @cache.get_server_for_key 'keyc'
  477. assert_equal 'two.example.com', server.host
  478. server = @cache.get_server_for_key 'keyd'
  479. assert_equal 'one.example.com', server.host
  480. end
  481. def test_get_server_for_key_no_servers
  482. @cache.servers = []
  483. e = assert_raise MemCache::MemCacheError do
  484. @cache.get_server_for_key 'key'
  485. end
  486. assert_equal 'No servers available', e.message
  487. end
  488. def test_get_server_for_key_spaces
  489. e = assert_raise ArgumentError do
  490. @cache.get_server_for_key 'space key'
  491. end
  492. assert_equal 'illegal character in key "space key"', e.message
  493. end
  494. def test_get_server_for_key_length
  495. @cache.get_server_for_key 'x' * 250
  496. long_key = 'x' * 251
  497. e = assert_raise ArgumentError do
  498. @cache.get_server_for_key long_key
  499. end
  500. assert_equal "key too long #{long_key.inspect}", e.message
  501. end
  502. def test_incr
  503. server = FakeServer.new
  504. server.socket.data.write "5\r\n"
  505. server.socket.data.rewind
  506. @cache.servers = []
  507. @cache.servers << server
  508. value = @cache.incr 'key'
  509. assert_equal "incr my_namespace:key 1\r\n",
  510. @cache.servers.first.socket.written.string
  511. assert_equal 5, value
  512. end
  513. def test_incr_not_found
  514. server = FakeServer.new
  515. server.socket.data.write "NOT_FOUND\r\n"
  516. server.socket.data.rewind
  517. @cache.servers = []
  518. @cache.servers << server
  519. value = @cache.incr 'key'
  520. assert_equal "incr my_namespace:key 1\r\n",
  521. @cache.servers.first.socket.written.string
  522. assert_equal nil, value
  523. end
  524. def test_incr_space_padding
  525. server = FakeServer.new
  526. server.socket.data.write "5 \r\n"
  527. server.socket.data.rewind
  528. @cache.servers = []
  529. @cache.servers << server
  530. value = @cache.incr 'key'
  531. assert_equal "incr my_namespace:key 1\r\n",
  532. @cache.servers.first.socket.written.string
  533. assert_equal 5, value
  534. end
  535. def test_make_cache_key
  536. assert_equal 'my_namespace:key', @cache.make_cache_key('key')
  537. @cache.namespace = nil
  538. assert_equal 'key', @cache.make_cache_key('key')
  539. end
  540. def test_servers
  541. server = FakeServer.new
  542. @cache.servers = []
  543. @cache.servers << server
  544. assert_equal [server], @cache.servers
  545. end
  546. def test_set
  547. server = FakeServer.new
  548. server.socket.data.write "STORED\r\n"
  549. server.socket.data.rewind
  550. @cache.servers = []
  551. @cache.servers << server
  552. @cache.set 'key', 'value'
  553. dumped = Marshal.dump('value')
  554. expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
  555. # expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
  556. assert_equal expected, server.socket.written.string
  557. end
  558. def test_set_expiry
  559. server = FakeServer.new
  560. server.socket.data.write "STORED\r\n"
  561. server.socket.data.rewind
  562. @cache.servers = []
  563. @cache.servers << server
  564. @cache.set 'key', 'value', 5
  565. dumped = Marshal.dump('value')
  566. expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
  567. assert_equal expected, server.socket.written.string
  568. end
  569. def test_set_raw
  570. server = FakeServer.new
  571. server.socket.data.write "STORED\r\n"
  572. server.socket.data.rewind
  573. @cache.servers = []
  574. @cache.servers << server
  575. @cache.set 'key', 'value', 0, true
  576. expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
  577. assert_equal expected, server.socket.written.string
  578. end
  579. def test_set_readonly
  580. cache = MemCache.new :readonly => true
  581. e = assert_raise MemCache::MemCacheError do
  582. cache.set 'key', 'value'
  583. end
  584. assert_equal 'Update of readonly cache', e.message
  585. end
  586. def test_check_size_on
  587. cache = MemCache.new :check_size => true
  588. server = FakeServer.new
  589. server.socket.data.write "STORED\r\n"
  590. server.socket.data.rewind
  591. cache.servers = []
  592. cache.servers << server
  593. e = assert_raise MemCache::MemCacheError do
  594. cache.set 'key', 'v' * 1048577
  595. end
  596. assert_equal 'Value too large, memcached can only store 1MB of data per key', e.message
  597. end
  598. def test_check_size_off
  599. cache = MemCache.new :check_size => false
  600. server = FakeServer.new
  601. server.socket.data.write "STORED\r\n"
  602. server.socket.data.rewind
  603. cache.servers = []
  604. cache.servers << server
  605. assert_nothing_raised do
  606. cache.set 'key', 'v' * 1048577
  607. end
  608. end
  609. def test_set_too_big
  610. server = FakeServer.new
  611. # Write two messages to the socket to test failover
  612. server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
  613. server.socket.data.rewind
  614. @cache.servers = []
  615. @cache.servers << server
  616. e = assert_raise MemCache::MemCacheError do
  617. @cache.set 'key', 'v'
  618. end
  619. assert_match /object too large for cache/, e.message
  620. end
  621. def test_prepend
  622. server = FakeServer.new
  623. server.socket.data.write "STORED\r\n"
  624. server.socket.data.rewind
  625. @cache.servers = []
  626. @cache.servers << server
  627. @cache.prepend 'key', 'value'
  628. dumped = Marshal.dump('value')
  629. expected = "prepend my_namespace:key 0 0 5\r\nvalue\r\n"
  630. assert_equal expected, server.socket.written.string
  631. end
  632. def test_append
  633. server = FakeServer.new
  634. server.socket.data.write "STORED\r\n"
  635. server.socket.data.rewind
  636. @cache.servers = []
  637. @cache.servers << server
  638. @cache.append 'key', 'value'
  639. expected = "append my_namespace:key 0 0 5\r\nvalue\r\n"
  640. assert_equal expected, server.socket.written.string
  641. end
  642. def test_replace
  643. server = FakeServer.new
  644. server.socket.data.write "STORED\r\n"
  645. server.socket.data.rewind
  646. @cache.servers = []
  647. @cache.servers << server
  648. @cache.replace 'key', 'value', 150
  649. dumped = Marshal.dump('value')
  650. expected = "replace my_namespace:key 0 150 #{dumped.length}\r\n#{dumped}\r\n"
  651. assert_equal expected, server.socket.written.string
  652. end
  653. def test_add
  654. server = FakeServer.new
  655. server.socket.data.write "STORED\r\n"
  656. server.socket.data.rewind
  657. @cache.servers = []
  658. @cache.servers << server
  659. @cache.add 'key', 'value'
  660. dumped = Marshal.dump('value')
  661. expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
  662. assert_equal expected, server.socket.written.string
  663. end
  664. def test_add_exists
  665. server = FakeServer.new
  666. server.socket.data.write "NOT_STORED\r\n"
  667. server.socket.data.rewind
  668. @cache.servers = []
  669. @cache.servers << server
  670. @cache.add 'key', 'value'
  671. dumped = Marshal.dump('value')
  672. expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
  673. assert_equal expected, server.socket.written.string
  674. end
  675. def test_add_expiry
  676. server = FakeServer.new
  677. server.socket.data.write "STORED\r\n"
  678. server.socket.data.rewind
  679. @cache.servers = []
  680. @cache.servers << server
  681. @cache.add 'key', 'value', 5
  682. dumped = Marshal.dump('value')
  683. expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
  684. assert_equal expected, server.socket.written.string
  685. end
  686. def test_add_raw
  687. server = FakeServer.new
  688. server.socket.data.write "STORED\r\n"
  689. server.socket.data.rewind
  690. @cache.servers = []
  691. @cache.servers << server
  692. @cache.add 'key', 'value', 0, true
  693. expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
  694. assert_equal expected, server.socket.written.string
  695. end
  696. def test_add_raw_int
  697. server = FakeServer.new
  698. server.socket.data.write "STORED\r\n"
  699. server.socket.data.rewind
  700. @cache.servers = []
  701. @cache.servers << server
  702. @cache.add 'key', 12, 0, true
  703. expected = "add my_namespace:key 0 0 2\r\n12\r\n"
  704. assert_equal expected, server.socket.written.string
  705. end
  706. def test_add_readonly
  707. cache = MemCache.new :readonly => true
  708. e = assert_raise MemCache::MemCacheError do
  709. cache.add 'key', 'value'
  710. end
  711. assert_equal 'Update of readonly cache', e.message
  712. end
  713. def test_delete
  714. server = FakeServer.new
  715. @cache.servers = []
  716. @cache.servers << server
  717. @cache.delete 'key'
  718. expected = "delete my_namespace:key 0\r\n"
  719. assert_equal expected, server.socket.written.string
  720. end
  721. def test_delete_with_expiry
  722. server = FakeServer.new
  723. @cache.servers = []
  724. @cache.servers << server
  725. @cache.delete 'key', 300
  726. expected = "delete my_namespace:key 300\r\n"
  727. assert_equal expected, server.socket.written.string
  728. end
  729. def test_flush_all
  730. @cache.servers = []
  731. 3.times { @cache.servers << FakeServer.new }
  732. @cache.flush_all
  733. expected = "flush_all\r\n"
  734. @cache.servers.each do |server|
  735. assert_equal expected, server.socket.written.string
  736. end
  737. end
  738. def test_flush_all_with_delay
  739. @cache.servers = []
  740. 3.times { @cache.servers << FakeServer.new }
  741. @cache.flush_all(10)
  742. @cache.servers.each_with_index do |server, idx|
  743. expected = "flush_all #{idx*10}\r\n"
  744. assert_equal expected, server.socket.written.string
  745. end
  746. end
  747. def test_flush_all_failure
  748. socket = FakeSocket.new
  749. # Write two messages to the socket to test failover
  750. socket.data.write "ERROR\r\nERROR\r\n"
  751. socket.data.rewind
  752. server = FakeServer.new socket
  753. @cache.servers = []
  754. @cache.servers << server
  755. assert_raise MemCache::MemCacheError do
  756. @cache.flush_all
  757. end
  758. assert_match /flush_all\r\n/, socket.written.string
  759. end
  760. def test_flush_all_for_real
  761. requirement(memcached_running?, 'A real memcached server must be running for testing flush_all') do
  762. cache = MemCache.new "localhost:11211", :namespace => "test_flush_all"
  763. k, v = "1234", "test"
  764. assert_nil cache.get(k)
  765. cache.set(k, v)
  766. assert_equal v, cache.get(k)
  767. cache.flush_all
  768. assert_nil cache.get(k)
  769. end
  770. end
  771. def test_stats
  772. socket = FakeSocket.new
  773. 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"
  774. socket.data.rewind
  775. server = FakeServer.new socket
  776. def server.host() 'localhost'; end
  777. def server.port() 11211; end
  778. @cache.servers = []
  779. @cache.servers << server
  780. expected = {
  781. 'localhost:11211' => {
  782. 'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
  783. 'rusage_user' => 1.0003, 'dummy' => 'ok'
  784. }
  785. }
  786. assert_equal expected, @cache.stats
  787. assert_equal "stats\r\n", socket.written.string
  788. end
  789. def test_basic_threaded_operations_should_work
  790. cache = MemCache.new :multithread => true,
  791. :namespace => 'my_namespace',
  792. :readonly => false
  793. server = FakeServer.new
  794. server.socket.data.write "STORED\r\n"
  795. server.socket.data.rewind
  796. cache.servers = []
  797. cache.servers << server
  798. assert cache.multithread
  799. assert_nothing_raised do
  800. cache.set "test", "test value"
  801. end
  802. output = server.socket.written.string
  803. assert_match /set my_namespace:test/, output
  804. assert_match /test value/, output
  805. end
  806. def test_basic_unthreaded_operations_should_work
  807. cache = MemCache.new :multithread => false,
  808. :namespace => 'my_namespace',
  809. :readonly => false
  810. server = FakeServer.new
  811. server.socket.data.write "STORED\r\n"
  812. server.socket.data.rewind
  813. cache.servers = []
  814. cache.servers << server
  815. assert !cache.multithread
  816. assert_nothing_raised do
  817. cache.set "test", "test value"
  818. end
  819. output = server.socket.written.string
  820. assert_match /set my_namespace:test/, output
  821. assert_match /test value/, output
  822. end
  823. def util_setup_fake_server
  824. server = FakeServer.new
  825. server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
  826. server.socket.data.write "\004\b\"\0170123456789\r\n"
  827. server.socket.data.write "END\r\n"
  828. server.socket.data.rewind
  829. @cache.servers = []
  830. @cache.servers << server
  831. return server
  832. end
  833. def util_setup_server(memcache, host, responses)
  834. server = MemCache::Server.new memcache, host
  835. server.instance_variable_set :@sock, StringIO.new(responses)
  836. @cache.servers = []
  837. @cache.servers << server
  838. return server
  839. end
  840. def test_crazy_multithreaded_access
  841. requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
  842. # Use a null logger to verify logging doesn't blow up at runtime
  843. cache = MemCache.new(['localhost:11211', '127.0.0.1:11211'], :logger => Logger.new('/dev/null'))
  844. cache.flush_all
  845. workers = []
  846. cache.set('f', 'zzz')
  847. assert_equal "STORED\r\n", (cache.cas('f') do |value|
  848. value << 'z'
  849. end)
  850. assert_equal 'zzzz', cache.get('f')
  851. # Have a bunch of threads perform a bunch of operations at the same time.
  852. # Verify the result of each operation to ensure the request and response
  853. # are not intermingled between threads.
  854. 10.times do
  855. workers << Thread.new do
  856. 100.times do
  857. cache.set('a', 9)
  858. cache.set('b', 11)
  859. cache.add('c', 10, 0, true)
  860. cache.set('d', 'a', 100, true)
  861. cache.set('e', 'x', 100, true)
  862. cache.set('f', 'zzz')
  863. assert_not_nil(cache.cas('f') do |value|
  864. value << 'z'
  865. end)
  866. cache.append('d', 'b')
  867. cache.prepend('e', 'y')
  868. assert_equal "NOT_STORED\r\n", cache.add('a', 11)
  869. assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
  870. inc = cache.incr('c', 10)
  871. assert_equal 0, inc % 5
  872. assert inc > 14
  873. assert cache.decr('c', 5) > 14
  874. assert_equal 11, cache.get('b')
  875. d = cache.get('d', true)
  876. assert_match /\Aab*\Z/, d
  877. e = cache.get('e', true)
  878. assert_match /\Ay*x\Z/, e
  879. end
  880. end
  881. end
  882. workers.each { |w| w.join }
  883. cache.flush_all
  884. end
  885. end
  886. end