/vendor/bundle/jruby/2.1/gems/rack-1.5.2/test/spec_session_memcache.rb

https://github.com/delowong/logstash · Ruby · 321 lines · 275 code · 42 blank · 4 comment · 2 complexity · b8f34bf7cdbf030a0f708e2170de05d2 MD5 · raw file

  1. begin
  2. require 'rack/session/memcache'
  3. require 'rack/lint'
  4. require 'rack/mock'
  5. require 'thread'
  6. describe Rack::Session::Memcache do
  7. session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key]
  8. session_match = /#{session_key}=([0-9a-fA-F]+);/
  9. incrementor = lambda do |env|
  10. env["rack.session"]["counter"] ||= 0
  11. env["rack.session"]["counter"] += 1
  12. Rack::Response.new(env["rack.session"].inspect).to_a
  13. end
  14. drop_session = Rack::Lint.new(proc do |env|
  15. env['rack.session.options'][:drop] = true
  16. incrementor.call(env)
  17. end)
  18. renew_session = Rack::Lint.new(proc do |env|
  19. env['rack.session.options'][:renew] = true
  20. incrementor.call(env)
  21. end)
  22. defer_session = Rack::Lint.new(proc do |env|
  23. env['rack.session.options'][:defer] = true
  24. incrementor.call(env)
  25. end)
  26. skip_session = Rack::Lint.new(proc do |env|
  27. env['rack.session.options'][:skip] = true
  28. incrementor.call(env)
  29. end)
  30. incrementor = Rack::Lint.new(incrementor)
  31. # test memcache connection
  32. Rack::Session::Memcache.new(incrementor)
  33. it "faults on no connection" do
  34. lambda{
  35. Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
  36. }.should.raise
  37. end
  38. it "connects to existing server" do
  39. test_pool = MemCache.new(incrementor, :namespace => 'test:rack:session')
  40. test_pool.namespace.should.equal 'test:rack:session'
  41. end
  42. it "passes options to MemCache" do
  43. pool = Rack::Session::Memcache.new(incrementor, :namespace => 'test:rack:session')
  44. pool.pool.namespace.should.equal 'test:rack:session'
  45. end
  46. it "creates a new cookie" do
  47. pool = Rack::Session::Memcache.new(incrementor)
  48. res = Rack::MockRequest.new(pool).get("/")
  49. res["Set-Cookie"].should.include("#{session_key}=")
  50. res.body.should.equal '{"counter"=>1}'
  51. end
  52. it "determines session from a cookie" do
  53. pool = Rack::Session::Memcache.new(incrementor)
  54. req = Rack::MockRequest.new(pool)
  55. res = req.get("/")
  56. cookie = res["Set-Cookie"]
  57. req.get("/", "HTTP_COOKIE" => cookie).
  58. body.should.equal '{"counter"=>2}'
  59. req.get("/", "HTTP_COOKIE" => cookie).
  60. body.should.equal '{"counter"=>3}'
  61. end
  62. it "determines session only from a cookie by default" do
  63. pool = Rack::Session::Memcache.new(incrementor)
  64. req = Rack::MockRequest.new(pool)
  65. res = req.get("/")
  66. sid = res["Set-Cookie"][session_match, 1]
  67. req.get("/?rack.session=#{sid}").
  68. body.should.equal '{"counter"=>1}'
  69. req.get("/?rack.session=#{sid}").
  70. body.should.equal '{"counter"=>1}'
  71. end
  72. it "determines session from params" do
  73. pool = Rack::Session::Memcache.new(incrementor, :cookie_only => false)
  74. req = Rack::MockRequest.new(pool)
  75. res = req.get("/")
  76. sid = res["Set-Cookie"][session_match, 1]
  77. req.get("/?rack.session=#{sid}").
  78. body.should.equal '{"counter"=>2}'
  79. req.get("/?rack.session=#{sid}").
  80. body.should.equal '{"counter"=>3}'
  81. end
  82. it "survives nonexistant cookies" do
  83. bad_cookie = "rack.session=blarghfasel"
  84. pool = Rack::Session::Memcache.new(incrementor)
  85. res = Rack::MockRequest.new(pool).
  86. get("/", "HTTP_COOKIE" => bad_cookie)
  87. res.body.should.equal '{"counter"=>1}'
  88. cookie = res["Set-Cookie"][session_match]
  89. cookie.should.not.match(/#{bad_cookie}/)
  90. end
  91. it "maintains freshness" do
  92. pool = Rack::Session::Memcache.new(incrementor, :expire_after => 3)
  93. res = Rack::MockRequest.new(pool).get('/')
  94. res.body.should.include '"counter"=>1'
  95. cookie = res["Set-Cookie"]
  96. res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
  97. res["Set-Cookie"].should.equal cookie
  98. res.body.should.include '"counter"=>2'
  99. puts 'Sleeping to expire session' if $DEBUG
  100. sleep 4
  101. res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
  102. res["Set-Cookie"].should.not.equal cookie
  103. res.body.should.include '"counter"=>1'
  104. end
  105. it "does not send the same session id if it did not change" do
  106. pool = Rack::Session::Memcache.new(incrementor)
  107. req = Rack::MockRequest.new(pool)
  108. res0 = req.get("/")
  109. cookie = res0["Set-Cookie"][session_match]
  110. res0.body.should.equal '{"counter"=>1}'
  111. res1 = req.get("/", "HTTP_COOKIE" => cookie)
  112. res1["Set-Cookie"].should.be.nil
  113. res1.body.should.equal '{"counter"=>2}'
  114. res2 = req.get("/", "HTTP_COOKIE" => cookie)
  115. res2["Set-Cookie"].should.be.nil
  116. res2.body.should.equal '{"counter"=>3}'
  117. end
  118. it "deletes cookies with :drop option" do
  119. pool = Rack::Session::Memcache.new(incrementor)
  120. req = Rack::MockRequest.new(pool)
  121. drop = Rack::Utils::Context.new(pool, drop_session)
  122. dreq = Rack::MockRequest.new(drop)
  123. res1 = req.get("/")
  124. session = (cookie = res1["Set-Cookie"])[session_match]
  125. res1.body.should.equal '{"counter"=>1}'
  126. res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
  127. res2["Set-Cookie"].should.equal nil
  128. res2.body.should.equal '{"counter"=>2}'
  129. res3 = req.get("/", "HTTP_COOKIE" => cookie)
  130. res3["Set-Cookie"][session_match].should.not.equal session
  131. res3.body.should.equal '{"counter"=>1}'
  132. end
  133. it "provides new session id with :renew option" do
  134. pool = Rack::Session::Memcache.new(incrementor)
  135. req = Rack::MockRequest.new(pool)
  136. renew = Rack::Utils::Context.new(pool, renew_session)
  137. rreq = Rack::MockRequest.new(renew)
  138. res1 = req.get("/")
  139. session = (cookie = res1["Set-Cookie"])[session_match]
  140. res1.body.should.equal '{"counter"=>1}'
  141. res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
  142. new_cookie = res2["Set-Cookie"]
  143. new_session = new_cookie[session_match]
  144. new_session.should.not.equal session
  145. res2.body.should.equal '{"counter"=>2}'
  146. res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
  147. res3.body.should.equal '{"counter"=>3}'
  148. # Old cookie was deleted
  149. res4 = req.get("/", "HTTP_COOKIE" => cookie)
  150. res4.body.should.equal '{"counter"=>1}'
  151. end
  152. it "omits cookie with :defer option but still updates the state" do
  153. pool = Rack::Session::Memcache.new(incrementor)
  154. count = Rack::Utils::Context.new(pool, incrementor)
  155. defer = Rack::Utils::Context.new(pool, defer_session)
  156. dreq = Rack::MockRequest.new(defer)
  157. creq = Rack::MockRequest.new(count)
  158. res0 = dreq.get("/")
  159. res0["Set-Cookie"].should.equal nil
  160. res0.body.should.equal '{"counter"=>1}'
  161. res0 = creq.get("/")
  162. res1 = dreq.get("/", "HTTP_COOKIE" => res0["Set-Cookie"])
  163. res1.body.should.equal '{"counter"=>2}'
  164. res2 = dreq.get("/", "HTTP_COOKIE" => res0["Set-Cookie"])
  165. res2.body.should.equal '{"counter"=>3}'
  166. end
  167. it "omits cookie and state update with :skip option" do
  168. pool = Rack::Session::Memcache.new(incrementor)
  169. count = Rack::Utils::Context.new(pool, incrementor)
  170. skip = Rack::Utils::Context.new(pool, skip_session)
  171. sreq = Rack::MockRequest.new(skip)
  172. creq = Rack::MockRequest.new(count)
  173. res0 = sreq.get("/")
  174. res0["Set-Cookie"].should.equal nil
  175. res0.body.should.equal '{"counter"=>1}'
  176. res0 = creq.get("/")
  177. res1 = sreq.get("/", "HTTP_COOKIE" => res0["Set-Cookie"])
  178. res1.body.should.equal '{"counter"=>2}'
  179. res2 = sreq.get("/", "HTTP_COOKIE" => res0["Set-Cookie"])
  180. res2.body.should.equal '{"counter"=>2}'
  181. end
  182. it "updates deep hashes correctly" do
  183. hash_check = proc do |env|
  184. session = env['rack.session']
  185. unless session.include? 'test'
  186. session.update :a => :b, :c => { :d => :e },
  187. :f => { :g => { :h => :i} }, 'test' => true
  188. else
  189. session[:f][:g][:h] = :j
  190. end
  191. [200, {}, [session.inspect]]
  192. end
  193. pool = Rack::Session::Memcache.new(hash_check)
  194. req = Rack::MockRequest.new(pool)
  195. res0 = req.get("/")
  196. session_id = (cookie = res0["Set-Cookie"])[session_match, 1]
  197. ses0 = pool.pool.get(session_id, true)
  198. req.get("/", "HTTP_COOKIE" => cookie)
  199. ses1 = pool.pool.get(session_id, true)
  200. ses1.should.not.equal ses0
  201. end
  202. # anyone know how to do this better?
  203. it "cleanly merges sessions when multithreaded" do
  204. unless $DEBUG
  205. 1.should.equal 1 # fake assertion to appease the mighty bacon
  206. next
  207. end
  208. warn 'Running multithread test for Session::Memcache'
  209. pool = Rack::Session::Memcache.new(incrementor)
  210. req = Rack::MockRequest.new(pool)
  211. res = req.get('/')
  212. res.body.should.equal '{"counter"=>1}'
  213. cookie = res["Set-Cookie"]
  214. session_id = cookie[session_match, 1]
  215. delta_incrementor = lambda do |env|
  216. # emulate disconjoinment of threading
  217. env['rack.session'] = env['rack.session'].dup
  218. Thread.stop
  219. env['rack.session'][(Time.now.usec*rand).to_i] = true
  220. incrementor.call(env)
  221. end
  222. tses = Rack::Utils::Context.new pool, delta_incrementor
  223. treq = Rack::MockRequest.new(tses)
  224. tnum = rand(7).to_i+5
  225. r = Array.new(tnum) do
  226. Thread.new(treq) do |run|
  227. run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
  228. end
  229. end.reverse.map{|t| t.run.join.value }
  230. r.each do |request|
  231. request['Set-Cookie'].should.equal cookie
  232. request.body.should.include '"counter"=>2'
  233. end
  234. session = pool.pool.get(session_id)
  235. session.size.should.equal tnum+1 # counter
  236. session['counter'].should.equal 2 # meeeh
  237. tnum = rand(7).to_i+5
  238. r = Array.new(tnum) do |i|
  239. app = Rack::Utils::Context.new pool, time_delta
  240. req = Rack::MockRequest.new app
  241. Thread.new(req) do |run|
  242. run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
  243. end
  244. end.reverse.map{|t| t.run.join.value }
  245. r.each do |request|
  246. request['Set-Cookie'].should.equal cookie
  247. request.body.should.include '"counter"=>3'
  248. end
  249. session = pool.pool.get(session_id)
  250. session.size.should.be tnum+1
  251. session['counter'].should.be 3
  252. drop_counter = proc do |env|
  253. env['rack.session'].delete 'counter'
  254. env['rack.session']['foo'] = 'bar'
  255. [200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
  256. end
  257. tses = Rack::Utils::Context.new pool, drop_counter
  258. treq = Rack::MockRequest.new(tses)
  259. tnum = rand(7).to_i+5
  260. r = Array.new(tnum) do
  261. Thread.new(treq) do |run|
  262. run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
  263. end
  264. end.reverse.map{|t| t.run.join.value }
  265. r.each do |request|
  266. request['Set-Cookie'].should.equal cookie
  267. request.body.should.include '"foo"=>"bar"'
  268. end
  269. session = pool.pool.get(session_id)
  270. session.size.should.be r.size+1
  271. session['counter'].should.be.nil?
  272. session['foo'].should.equal 'bar'
  273. end
  274. end
  275. rescue RuntimeError
  276. $stderr.puts "Skipping Rack::Session::Memcache tests. Start memcached and try again."
  277. rescue LoadError
  278. $stderr.puts "Skipping Rack::Session::Memcache tests (Memcache is required). `gem install memcache-client` and try again."
  279. end