PageRenderTime 63ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/test/test_mem_cache.rb

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