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